Merge pull request #1059 from devanlai/can-loopback-wip

Implement some CAN modes for the LPC1549/LPC11Cxx/LPC1768
pull/1072/merge
Martin Kojtal 2015-04-30 09:03:12 +01:00
commit 334b3418df
6 changed files with 198 additions and 5 deletions

View File

@ -45,8 +45,8 @@ typedef enum {
MODE_RESET,
MODE_NORMAL,
MODE_SILENT,
MODE_TEST_GLOBAL,
MODE_TEST_LOCAL,
MODE_TEST_GLOBAL,
MODE_TEST_SILENT
} CanMode;

View File

@ -45,7 +45,42 @@ static inline void can_enable(can_t *obj) {
}
int can_mode(can_t *obj, CanMode mode) {
return 0; // not implemented
int success = 0;
switch (mode) {
case MODE_RESET:
LPC_CAN->CNTL &=~CANCNTL_TEST;
can_disable(obj);
success = 1;
break;
case MODE_NORMAL:
LPC_CAN->CNTL &=~CANCNTL_TEST;
can_enable(obj);
success = 1;
break;
case MODE_SILENT:
LPC_CAN->CNTL |= CANCNTL_TEST;
LPC_CAN->TEST |= CANTEST_SILENT;
LPC_CAN->TEST &=~CANTEST_LBACK;
success = 1;
break;
case MODE_TEST_LOCAL:
LPC_CAN->CNTL |= CANCNTL_TEST;
LPC_CAN->TEST &=~CANTEST_SILENT;
LPC_CAN->TEST |= CANTEST_LBACK;
success = 1;
break;
case MODE_TEST_SILENT:
LPC_CAN->CNTL |= CANCNTL_TEST;
LPC_CAN->TEST |= (CANCNTL_LBACK | CANTEST_SILENT);
success = 1;
break;
case MODE_TEST_GLOBAL:
default:
success = 0;
break;
}
return success;
}
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) {

View File

@ -56,6 +56,21 @@
#define CANIFn_CMDMSK_RD (0UL << 7)
#define CANIFn_CMDREQ_BUSY (1UL << 15)
#define CANCNTL_INIT (1 << 0) // Initialization
#define CANCNTL_IE (1 << 1) // Module interrupt enable
#define CANCNTL_SIE (1 << 2) // Status change interrupt enable
#define CANCNTL_EIE (1 << 3) // Error interrupt enable
#define CANCNTL_DAR (1 << 5) // Disable automatic retransmission
#define CANCNTL_CCE (1 << 6) // Configuration change enable
#define CANCNTL_TEST (1 << 7) // Test mode enable
#define CANTEST_BASIC (1 << 2) // Basic mode
#define CANTEST_SILENT (1 << 3) // Silent mode
#define CANTEST_LBACK (1 << 4) // Loop back mode
#define CANTEST_TX_MASK 0x0060 // Control of CAN_TXD pins
#define CANTEST_TX_SHIFT 5
#define CANTEST_RX (1 << 7) // Monitors the actual value of the CAN_RXD pin.
static uint32_t can_irq_id = 0;
static can_irq_handler irq_handler;
@ -70,7 +85,42 @@ static inline void can_enable(can_t *obj) {
}
int can_mode(can_t *obj, CanMode mode) {
return 0; // not implemented
int success = 0;
switch (mode) {
case MODE_RESET:
LPC_C_CAN0->CANCNTL &=~CANCNTL_TEST;
can_disable(obj);
success = 1;
break;
case MODE_NORMAL:
LPC_C_CAN0->CANCNTL &=~CANCNTL_TEST;
can_enable(obj);
success = 1;
break;
case MODE_SILENT:
LPC_C_CAN0->CANCNTL |= CANCNTL_TEST;
LPC_C_CAN0->CANTEST |= CANTEST_SILENT;
LPC_C_CAN0->CANTEST &=~ CANTEST_LBACK;
success = 1;
break;
case MODE_TEST_LOCAL:
LPC_C_CAN0->CANCNTL |= CANCNTL_TEST;
LPC_C_CAN0->CANTEST &=~CANTEST_SILENT;
LPC_C_CAN0->CANTEST |= CANTEST_LBACK;
success = 1;
break;
case MODE_TEST_SILENT:
LPC_C_CAN0->CANCNTL |= CANCNTL_TEST;
LPC_C_CAN0->CANTEST |= (CANTEST_LBACK | CANTEST_SILENT);
success = 1;
break;
case MODE_TEST_GLOBAL:
default:
success = 0;
break;
}
return success;
}
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) {

View File

@ -79,7 +79,45 @@ static inline void can_enable(can_t *obj) {
}
int can_mode(can_t *obj, CanMode mode) {
return 0; // not implemented
int success = 0;
switch (mode) {
case MODE_RESET:
// Clear all special modes
can_reset(obj);
obj->dev->MOD &=~ 0x06;
success = 1;
break;
case MODE_NORMAL:
// Clear all special modes
can_disable(obj);
obj->dev->MOD &=~ 0x06;
can_enable(obj);
success = 1;
break;
case MODE_SILENT:
// Set listen-only mode and clear self-test mode
can_disable(obj);
obj->dev->MOD |= 0x02;
obj->dev->MOD &=~ 0x04;
can_enable(obj);
success = 1;
break;
case MODE_TEST_LOCAL:
// Set self-test mode and clear listen-only mode
can_disable(obj);
obj->dev->MOD |= 0x04;
obj->dev->MOD &=~ 0x02;
can_enable(obj);
success = 1;
break;
case MODE_TEST_SILENT:
case MODE_TEST_GLOBAL:
default:
success = 0;
break;
}
return success;
}
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle) {
@ -316,6 +354,12 @@ int can_write(can_t *obj, CAN_Message msg, int cc) {
const unsigned int *buf = (const unsigned int *)&m;
CANStatus = obj->dev->SR;
// Send the message to ourself if in a test mode
if (obj->dev->MOD & 0x04) {
cc = 1;
}
if (CANStatus & 0x00000004) {
obj->dev->TFI1 = buf[0] & 0xC00F0000;
obj->dev->TID1 = buf[1];

View File

@ -0,0 +1,50 @@
#include "mbed.h"
#include "test_env.h"
#if defined(TARGET_LPC1549)
CAN can1(D9, D8);
#elif defined(TARGET_LPC1768) || defined(TARGET_LPC4088)
CAN can1(p9, p10);
#endif
#define TEST_ITERATIONS 127
int main() {
MBED_HOSTTEST_TIMEOUT(20);
MBED_HOSTTEST_SELECT(dev_null);
MBED_HOSTTEST_DESCRIPTION(CAN Loopback);
MBED_HOSTTEST_START("MBED_A27");
can1.mode(CAN::Reset);
if (!can1.mode(CAN::LocalTest)) {
printf("Mode change failed\n");
}
char success_count = 0;
for (char i=0; i < TEST_ITERATIONS; i++) {
unsigned int id = 1337;
CANMessage tx_msg(id, &i, sizeof(i));
bool sent = false;
if (can1.write(tx_msg)) {
printf("Sent %u: %d\n", id, i);
sent = true;
}
wait_ms(50);
bool read = false;
CANMessage rx_msg;
if (can1.read(rx_msg)) {
printf("Read %u: %d\n", rx_msg.id, rx_msg.data[0]);
read = (rx_msg.id == id) && (rx_msg.data[0] == i);
}
bool success = sent && read;
if (success) {
success_count++;
}
}
MBED_HOSTTEST_RESULT(success_count == TEST_ITERATIONS);
}

View File

@ -80,7 +80,12 @@ Wiring:
* i2c_eeprom:
* LPC1*: (SDA=p28 , SCL=p27)
* KL25Z: (SDA=PTE0, SCL=PTE1)
* can_transceiver:
* LPC1768: (RX=p9, TX=p10)
* LPC1549: (RX=D9, TX=D8)
* LPC4088: (RX=p9, TX=p10)
"""
TESTS = [
# Automated MBED tests
@ -270,6 +275,15 @@ TESTS = [
"automated": True,
"duration": 10,
},
{
"id": "MBED_A27", "description": "CAN loopback test",
"source_dir": join(TEST_DIR, "mbed", "can_loopback"),
"dependencies": [MBED_LIBRARIES, TEST_MBED_LIB],
"automated": True,
"duration": 20,
"peripherals": ["can_transceiver"],
"mcu": ["LPC1549", "LPC1768"],
},
{
"id": "MBED_BLINKY", "description": "Blinky",
"source_dir": join(TEST_DIR, "mbed", "blinky"),