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::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() {
// No lock needed in destructor
can_irq_free(&_can);

View File

@ -111,6 +111,15 @@ public:
* @endcode
*/
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();
/** 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

@ -57,9 +57,10 @@ typedef void (*can_irq_handler)(uint32_t id, CanIrqType type);
typedef struct can_s can_t;
void can_init (can_t *obj, PinName rd, PinName td);
void can_free (can_t *obj);
int can_frequency(can_t *obj, int hz);
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);
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_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_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
obj->can = (CANName)pinmap_merge(can_td, can_rd);
@ -69,12 +69,18 @@
PA0 = 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);
}
void can_init(can_t *obj, PinName rd, PinName td)
{
can_init_freq(obj, rd, td, 500000);
}
void can_free(can_t *obj)
{

View File

@ -43,8 +43,8 @@
{NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL}
};
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_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
@ -75,12 +75,18 @@
PA2 = 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);
}
void can_init(can_t *obj, PinName rd, PinName td)
{
can_init_freq(obj, rd, td, 500000);
}
void can_free(can_t *obj)
{

View File

@ -268,26 +268,30 @@ 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
LPC_SYSCON->PRESETCTRL |= PRESETCTRL_CAN_RST_N;
LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_CAN;
// Enable Initialization mode
if (!(LPC_CAN->CNTL & CANCNTL_INIT)) {
LPC_CAN->CNTL |= CANCNTL_INIT;
}
can_frequency(obj, 125000);
can_frequency(obj, hz);
// Resume operation
LPC_CAN->CNTL &= ~CANCNTL_INIT;
while ( LPC_CAN->CNTL & CANCNTL_INIT );
// Initialize RX message object
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) {
LPC_SYSCON->SYSAHBCLKCTRL &= ~(SYSAHBCLKCTRL_CAN);
LPC_SYSCON->PRESETCTRL &= ~(PRESETCTRL_CAN_RST_N);

View File

@ -415,8 +415,7 @@ int can_config_txmsgobj(can_t *obj) {
return 1;
}
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
LPC_SYSCON->SYSAHBCLKCTRL1 |= (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] |= (rd << 16) | (td << 8);
can_frequency(obj, 100000);
can_frequency(obj, hz);
// Resume operation
LPC_C_CAN0->CANCNTL &= ~(1UL << 0);
@ -442,6 +441,10 @@ void can_init(can_t *obj, PinName rd, PinName td) {
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) {
LPC_SYSCON->SYSAHBCLKCTRL1 &= ~(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_td = (CANName)pinmap_peripheral(td, PinMap_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);
obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000);
can_frequency(obj, hz);
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) {
switch ((int)obj->dev) {
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_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
obj->dev = (LPC_CAN_TypeDef *)pinmap_merge(can_rd, can_td);
@ -252,19 +252,23 @@ void can_init(can_t *obj, PinName rd, PinName td) {
pinmap_pinout(rd, PinMap_CAN_RD);
pinmap_pinout(td, PinMap_CAN_TD);
switch ((int)obj->dev) {
case CAN_1: obj->index = 0; break;
case CAN_2: obj->index = 1; break;
}
can_reset(obj);
obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000);
can_frequency(obj, hz);
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) {
switch ((int)obj->dev) {
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_td = (CANName)pinmap_peripheral(td, PinMap_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);
obj->dev->IER = 0; // Disable Interrupts
can_frequency(obj, 100000);
can_frequency(obj, hz);
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) {
switch ((int)obj->dev) {
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);
}
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;
/* determine the CAN to use */
@ -573,6 +573,13 @@ void can_init(can_t *obj, PinName rd, PinName td) {
/* pin out the can pins */
pinmap_pinout(rd, PinMap_CAN_RD);
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) {

View File

@ -556,7 +556,7 @@ static void can4_bus_err_irq(void) {
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;
/* determine the CAN to use */
@ -590,6 +590,13 @@ void can_init(can_t *obj, PinName rd, PinName td) {
/* pin out the can pins */
pinmap_pinout(rd, PinMap_CAN_RD);
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) {

View File

@ -275,8 +275,8 @@ const PinMap PinMap_SPI_SSEL[] = {
};
const PinMap PinMap_CAN_RD[] = {
{PB_8 , 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)},
{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)}, // warning: pin used by USB
{NC, NC, 0}
};

View File

@ -30,6 +30,11 @@ static uint32_t can_irq_ids[CAN_NUM] = {0};
static can_irq_handler irq_handler;
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_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");
}
// Set initial CAN frequency to 100 kb/s
can_frequency(obj, 100000);
// Set initial CAN frequency to requested kb/s
can_frequency(obj, hz);
uint32_t filter_number = (obj->can == CAN_1) ? 0 : 14;
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_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)
@ -227,16 +232,16 @@ int can_write(can_t *obj, CAN_Message msg, int cc)
} else {
can->sTxMailBox[transmitmailbox].TIR |= ((msg.id << 3) | CAN_ID_EXT | msg.type);
}
/* Set up the DLC */
can->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
can->sTxMailBox[transmitmailbox].TDTR |= (msg.len & (uint8_t)0x0000000F);
/* Set up the data field */
can->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)msg.data[3] << 24) |
((uint32_t)msg.data[2] << 16) |
((uint32_t)msg.data[1] << 8) |
((uint32_t)msg.data[0]));
((uint32_t)msg.data[2] << 16) |
((uint32_t)msg.data[1] << 8) |
((uint32_t)msg.data[0]));
can->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)msg.data[7] << 24) |
((uint32_t)msg.data[6] << 16) |
((uint32_t)msg.data[5] << 8) |

View File

@ -339,6 +339,19 @@ TESTS = [
"automated": True,
"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",
"source_dir": join(TEST_DIR, "mbed", "blinky"),