mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #1059 from devanlai/can-loopback-wip
Implement some CAN modes for the LPC1549/LPC11Cxx/LPC1768pull/1072/merge
commit
334b3418df
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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"),
|
||||
|
|
Loading…
Reference in New Issue