Merge pull request #4165 from adustm/can_init

fix #3863 Add an mbed API that allows the init of the CAN at the bus frequency
pull/4332/merge
Sam Grove 2017-05-26 10:45:19 -05:00 committed by GitHub
commit d11289b576
16 changed files with 226 additions and 42 deletions

View File

@ -34,6 +34,17 @@ CAN::CAN(PinName rd, PinName td) : _can(), _irq() {
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this); can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
} }
CAN::CAN(PinName rd, PinName td, int hz) : _can(), _irq() {
// No lock needed in constructor
for (int i = 0; i < sizeof _irq / sizeof _irq[0]; i++) {
_irq[i].attach(donothing);
}
can_init_freq(&_can, rd, td, hz);
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
}
CAN::~CAN() { CAN::~CAN() {
// No lock needed in destructor // No lock needed in destructor
can_irq_free(&_can); can_irq_free(&_can);

View File

@ -111,6 +111,15 @@ public:
* @endcode * @endcode
*/ */
CAN(PinName rd, PinName td); CAN(PinName rd, PinName td);
/** Initialize CAN interface and set the frequency
*
* @param rd the rd pin
* @param td the td pin
* @param hz the bus frequency in hertz
*/
CAN(PinName rd, PinName td, int hz);
virtual ~CAN(); virtual ~CAN();
/** Set the frequency of the CAN interface /** Set the frequency of the CAN interface

View File

@ -0,0 +1,100 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "test_env.h"
#if !DEVICE_CAN
#error [NOT_SUPPORTED] CAN not supported
#endif
#if defined(TARGET_LPC1549)
#define CAN_RD D9
#define CAN_TD D8
#elif defined(TARGET_LPC1768) || defined(TARGET_LPC4088)
#define CAN_RD p9
#define CAN_TD p10
#elif defined(TARGET_B96B_F446VE)
#define CAN_RD PD_0
#define CAN_TD PD_1
#elif defined(TARGET_VK_RZ_A1H)
#define CAN_RD P5_9
#define CAN_TD P5_10
#elif defined(TARGET_NUCLEO_F042K6) || \
defined(TARGET_NUCLEO_F072RB) || \
defined(TARGET_NUCLEO_F091RC) || \
defined(TARGET_NUCLEO_F302R8) || \
defined(TARGET_NUCLEO_F303RE) || \
defined(TARGET_NUCLEO_F303K8) || \
defined(TARGET_NUCLEO_F334R8) || \
defined(TARGET_NUCLEO_F412ZG) || \
defined(TARGET_DISCO_F429ZI) || \
defined(TARGET_NUCLEO_F446RE) || \
defined(TARGET_NUCLEO_F746ZG) || \
defined(TARGET_NUCLEO_L432KC) || \
defined(TARGET_DISCO_L476VG) || \
defined(TARGET_NUCLEO_L476RG)
#define CAN_RD PA_11
#define CAN_TD PA_12
#elif defined(TARGET_NUCLEO_F103RB) || \
defined(TARGET_NUCLEO_F207ZG) || \
defined(TARGET_DISCO_F303VC) || \
defined(TARGET_NUCLEO_F303ZE) || \
defined(TARGET_NUCLEO_F412ZG) || \
defined(TARGET_NUCLEO_F429ZI) || \
defined(TARGET_NUCLEO_F439ZI) || \
defined(TARGET_NUCLEO_F446ZE) || \
defined(TARGET_DISCO_F469NI) || \
defined(TARGET_DISCO_F746NG) || \
defined(TARGET_NUCLEO_F756ZG) || \
defined(TARGET_NUCLEO_F767ZI) || \
defined(TARGET_DISCO_F769NI) || \
defined(TARGET_NUCLEO_L486RG)
#define CAN_RD PB_8
#define CAN_TD PB_9
#endif
int result = true;
void Check_CAN_Frequency(int CanFrequency)
{
printf("Init CAN at %d Hz\n", CanFrequency);
CAN can_object(CAN_RD, CAN_TD, CanFrequency);
#if !defined(TARGET_VK_RZ_A1H)
can_object.mode(CAN::Reset);
#endif
if (!can_object.mode(CAN::LocalTest)) {
printf("CAN MODE_TEST_LOCAL failed\n");
result = false;
}
}
int main()
{
MBED_HOSTTEST_TIMEOUT(20);
MBED_HOSTTEST_SELECT(dev_null);
MBED_HOSTTEST_DESCRIPTION(CAN API at different frequency);
MBED_HOSTTEST_START("MBED_A30");
const int frequency_table[] = {10000, 50000, 100000, 500000, 1000000};
for (uint32_t i = 0; i < sizeof(frequency_table)/sizeof(int); i++) {
Check_CAN_Frequency(frequency_table[i]);
}
MBED_HOSTTEST_RESULT(result);
}

View File

@ -58,8 +58,9 @@ typedef void (*can_irq_handler)(uint32_t id, CanIrqType type);
typedef struct can_s can_t; typedef struct can_s can_t;
void can_init (can_t *obj, PinName rd, PinName td); void can_init (can_t *obj, PinName rd, PinName td);
void can_init_freq (can_t *obj, PinName rd, PinName td, int hz);
void can_free (can_t *obj); void can_free (can_t *obj);
int can_frequency(can_t *obj, int hz); int can_frequency (can_t *obj, int hz);
void can_irq_init (can_t *obj, can_irq_handler handler, uint32_t id); void can_irq_init (can_t *obj, can_irq_handler handler, uint32_t id);
void can_irq_free (can_t *obj); void can_irq_free (can_t *obj);

View File

@ -42,8 +42,8 @@
}; };
void can_init(can_t *obj, PinName rd, PinName td) void can_init_freq(can_t *obj, PinName rd, PinName td, int hz)
{ {
uint32_t can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); uint32_t can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
uint32_t can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); uint32_t can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
obj->can = (CANName)pinmap_merge(can_td, can_rd); obj->can = (CANName)pinmap_merge(can_td, can_rd);
@ -69,12 +69,18 @@
PA0 = 0x00; PA0 = 0x00;
PA1 = 0x00; PA1 = 0x00;
CAN_Open((CAN_T *)NU_MODBASE(obj->can), 500000, CAN_NORMAL_MODE); CAN_Open((CAN_T *)NU_MODBASE(obj->can), hz, CAN_NORMAL_MODE);
can_filter(obj, 0, 0, CANStandard, 0); can_filter(obj, 0, 0, CANStandard, 0);
} }
void can_init(can_t *obj, PinName rd, PinName td)
{
can_init_freq(obj, rd, td, 500000);
}
void can_free(can_t *obj) void can_free(can_t *obj)
{ {

View File

@ -44,7 +44,7 @@
}; };
void can_init(can_t *obj, PinName rd, PinName td) void can_init_freq(can_t *obj, PinName rd, PinName td, int hz)
{ {
uint32_t can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); uint32_t can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
uint32_t can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); uint32_t can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
@ -75,12 +75,18 @@
PA2 = 0x00; PA2 = 0x00;
PA3 = 0x00; PA3 = 0x00;
CAN_Open((CAN_T *)NU_MODBASE(obj->can), 500000, CAN_NORMAL_MODE); CAN_Open((CAN_T *)NU_MODBASE(obj->can), hz, CAN_NORMAL_MODE);
can_filter(obj, 0, 0, CANStandard, 0); can_filter(obj, 0, 0, CANStandard, 0);
} }
void can_init(can_t *obj, PinName rd, PinName td)
{
can_init_freq(obj, rd, td, 500000);
}
void can_free(can_t *obj) void can_free(can_t *obj)
{ {

View File

@ -268,7 +268,7 @@ int can_config_rxmsgobj(can_t *obj) {
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
// Enable power and clock // Enable power and clock
LPC_SYSCON->PRESETCTRL |= PRESETCTRL_CAN_RST_N; LPC_SYSCON->PRESETCTRL |= PRESETCTRL_CAN_RST_N;
LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_CAN; LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_CAN;
@ -278,7 +278,7 @@ void can_init(can_t *obj, PinName rd, PinName td) {
LPC_CAN->CNTL |= CANCNTL_INIT; LPC_CAN->CNTL |= CANCNTL_INIT;
} }
can_frequency(obj, 125000); can_frequency(obj, hz);
// Resume operation // Resume operation
LPC_CAN->CNTL &= ~CANCNTL_INIT; LPC_CAN->CNTL &= ~CANCNTL_INIT;
@ -288,6 +288,10 @@ void can_init(can_t *obj, PinName rd, PinName td) {
can_config_rxmsgobj(obj); can_config_rxmsgobj(obj);
} }
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 125000);
}
void can_free(can_t *obj) { void can_free(can_t *obj) {
LPC_SYSCON->SYSAHBCLKCTRL &= ~(SYSAHBCLKCTRL_CAN); LPC_SYSCON->SYSAHBCLKCTRL &= ~(SYSAHBCLKCTRL_CAN);
LPC_SYSCON->PRESETCTRL &= ~(PRESETCTRL_CAN_RST_N); LPC_SYSCON->PRESETCTRL &= ~(PRESETCTRL_CAN_RST_N);

View File

@ -415,8 +415,7 @@ int can_config_txmsgobj(can_t *obj) {
return 1; return 1;
} }
void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
void can_init(can_t *obj, PinName rd, PinName td) {
// Enable power and clock // Enable power and clock
LPC_SYSCON->SYSAHBCLKCTRL1 |= (1UL << 7); LPC_SYSCON->SYSAHBCLKCTRL1 |= (1UL << 7);
LPC_SYSCON->PRESETCTRL1 |= (1UL << 7); LPC_SYSCON->PRESETCTRL1 |= (1UL << 7);
@ -430,7 +429,7 @@ void can_init(can_t *obj, PinName rd, PinName td) {
LPC_SWM->PINASSIGN[6] &= ~(0x00FFFF00L); LPC_SWM->PINASSIGN[6] &= ~(0x00FFFF00L);
LPC_SWM->PINASSIGN[6] |= (rd << 16) | (td << 8); LPC_SWM->PINASSIGN[6] |= (rd << 16) | (td << 8);
can_frequency(obj, 100000); can_frequency(obj, hz);
// Resume operation // Resume operation
LPC_C_CAN0->CANCNTL &= ~(1UL << 0); LPC_C_CAN0->CANCNTL &= ~(1UL << 0);
@ -442,6 +441,10 @@ void can_init(can_t *obj, PinName rd, PinName td) {
can_config_txmsgobj(obj); can_config_txmsgobj(obj);
} }
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
}
void can_free(can_t *obj) { void can_free(can_t *obj) {
LPC_SYSCON->SYSAHBCLKCTRL1 &= ~(1UL << 7); LPC_SYSCON->SYSAHBCLKCTRL1 &= ~(1UL << 7);
LPC_SYSCON->PRESETCTRL1 &= ~(1UL << 7); LPC_SYSCON->PRESETCTRL1 &= ~(1UL << 7);

View File

@ -292,7 +292,7 @@ static unsigned int can_speed(unsigned int sclk, unsigned int pclk, unsigned int
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td); obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
@ -313,11 +313,15 @@ void can_init(can_t *obj, PinName rd, PinName td) {
can_reset(obj); can_reset(obj);
obj->dev->IER = 0; // Disable Interrupts obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000); can_frequency(obj, hz);
LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
} }
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
}
void can_free(can_t *obj) { void can_free(can_t *obj) {
switch ((int)obj->dev) { switch ((int)obj->dev) {
case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break; case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break;

View File

@ -239,7 +239,7 @@ static unsigned int can_speed(unsigned int pclk, unsigned int cclk, unsigned cha
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td); obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
@ -260,11 +260,15 @@ void can_init(can_t *obj, PinName rd, PinName td) {
can_reset(obj); can_reset(obj);
obj->dev->IER = 0; // Disable Interrupts obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000); can_frequency(obj, hz);
LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
} }
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
}
void can_free(can_t *obj) { void can_free(can_t *obj) {
switch ((int)obj->dev) { switch ((int)obj->dev) {
case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break; case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break;

View File

@ -236,7 +236,7 @@ static unsigned int can_speed(unsigned int pclk, unsigned int cclk, unsigned cha
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td); obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
@ -257,11 +257,15 @@ void can_init(can_t *obj, PinName rd, PinName td) {
can_reset(obj); can_reset(obj);
obj->dev->IER = 0; // Disable Interrupts obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000); can_frequency(obj, hz);
LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter LPC_CANAF->AFMR = ACCF_BYPASS; // Bypass Filter
} }
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
}
void can_free(can_t *obj) { void can_free(can_t *obj) {
switch ((int)obj->dev) { switch ((int)obj->dev) {
case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break; case CAN_1: LPC_SC->PCONP &= ~(1 << 13); break;

View File

@ -539,7 +539,7 @@ static void can4_bus_err_irq(void) {
can_err_irq(CAN_4, IRQ_BUS); can_err_irq(CAN_4, IRQ_BUS);
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
__IO uint32_t *dmy_ctr; __IO uint32_t *dmy_ctr;
/* determine the CAN to use */ /* determine the CAN to use */
@ -573,6 +573,13 @@ void can_init(can_t *obj, PinName rd, PinName td) {
/* pin out the can pins */ /* pin out the can pins */
pinmap_pinout(rd, PinMap_CAN_RD); pinmap_pinout(rd, PinMap_CAN_RD);
pinmap_pinout(td, PinMap_CAN_TD); pinmap_pinout(td, PinMap_CAN_TD);
/* set can frequency */
can_frequency(obj, hz);
}
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
} }
void can_free(can_t *obj) { void can_free(can_t *obj) {

View File

@ -556,7 +556,7 @@ static void can4_bus_err_irq(void) {
can_err_irq(CAN_4, IRQ_BUS); can_err_irq(CAN_4, IRQ_BUS);
} }
void can_init(can_t *obj, PinName rd, PinName td) { void can_init_freq(can_t *obj, PinName rd, PinName td, int hz) {
__IO uint32_t *dmy_ctr; __IO uint32_t *dmy_ctr;
/* determine the CAN to use */ /* determine the CAN to use */
@ -590,6 +590,13 @@ void can_init(can_t *obj, PinName rd, PinName td) {
/* pin out the can pins */ /* pin out the can pins */
pinmap_pinout(rd, PinMap_CAN_RD); pinmap_pinout(rd, PinMap_CAN_RD);
pinmap_pinout(td, PinMap_CAN_TD); pinmap_pinout(td, PinMap_CAN_TD);
/* set can frequency */
can_frequency(obj, hz);
}
void can_init(can_t *obj, PinName rd, PinName td) {
can_init_freq(obj, rd, td, 100000);
} }
void can_free(can_t *obj) { void can_free(can_t *obj) {

View File

@ -275,8 +275,8 @@ const PinMap PinMap_SPI_SSEL[] = {
}; };
const PinMap PinMap_CAN_RD[] = { const PinMap PinMap_CAN_RD[] = {
{PB_8 , CAN_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, {PB_8 , CAN_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, // warning: pin used by gyroscope
{PA_11, CAN_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, {PA_11, CAN_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF9_CAN1)}, // warning: pin used by USB
{NC, NC, 0} {NC, NC, 0}
}; };

View File

@ -30,6 +30,11 @@ static uint32_t can_irq_ids[CAN_NUM] = {0};
static can_irq_handler irq_handler; static can_irq_handler irq_handler;
void can_init(can_t *obj, PinName rd, PinName td) void can_init(can_t *obj, PinName rd, PinName td)
{
can_init_freq(obj, rd, td, 100000);
}
void can_init_freq (can_t *obj, PinName rd, PinName td, int hz)
{ {
CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD); CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD); CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
@ -80,8 +85,8 @@ void can_init(can_t *obj, PinName rd, PinName td)
error("Cannot initialize CAN"); error("Cannot initialize CAN");
} }
// Set initial CAN frequency to 100 kb/s // Set initial CAN frequency to requested kb/s
can_frequency(obj, 100000); can_frequency(obj, hz);
uint32_t filter_number = (obj->can == CAN_1) ? 0 : 14; uint32_t filter_number = (obj->can == CAN_1) ? 0 : 14;
can_filter(obj, 0, 0, CANStandard, filter_number); can_filter(obj, 0, 0, CANStandard, filter_number);
@ -99,7 +104,7 @@ void can_irq_free(can_t *obj)
can->IER &= ~(CAN_IT_FMP0 | CAN_IT_FMP1 | CAN_IT_TME | \ can->IER &= ~(CAN_IT_FMP0 | CAN_IT_FMP1 | CAN_IT_TME | \
CAN_IT_ERR | CAN_IT_EPV | CAN_IT_BOF); CAN_IT_ERR | CAN_IT_EPV | CAN_IT_BOF);
can_irq_ids[obj->can] = 0; can_irq_ids[obj->index] = 0;
} }
void can_free(can_t *obj) void can_free(can_t *obj)

View File

@ -339,6 +339,19 @@ TESTS = [
"automated": True, "automated": True,
"peripherals": ["i2c_loop"] "peripherals": ["i2c_loop"]
}, },
{
"id": "MBED_A30", "description": "CAN API",
"source_dir": join(TEST_DIR, "mbed", "can_api"),
"dependencies": [MBED_LIBRARIES, TEST_MBED_LIB],
"automated": True,
"mcu": ["LPC1549", "LPC1768","B96B_F446VE", "VK_RZ_A1H",
"NUCLEO_F091RC", "NUCLEO_F072RB", "NUCLEO_F042K6", "NUCLEO_F334R8", "NUCLEO_F207ZG",
"NUCLEO_F303RE", "NUCLEO_F303K8", "NUCLEO_F303ZE", "NUCLEO_F302R8", "NUCLEO_F446RE","NUCLEO_F446ZE",
"DISCO_F469NI", "DISCO_F429ZI", "NUCLEO_F103RB", "NUCLEO_F746ZG",
"NUCLEO_F429ZI", "NUCLEO_F439ZI", "NUCLEO_F756ZG", "NUCLEO_L486RG",
"DISCO_F746NG", "DISCO_L476VG", "NUCLEO_L476RG", "NUCLEO_L432KC",
"DISCO_F769NI", "NUCLEO_F767ZI", "DISCO_F303VC", "NUCLEO_F412ZG"]
},
{ {
"id": "MBED_BLINKY", "description": "Blinky", "id": "MBED_BLINKY", "description": "Blinky",
"source_dir": join(TEST_DIR, "mbed", "blinky"), "source_dir": join(TEST_DIR, "mbed", "blinky"),