From 23816ef42f6039cfadfbab6fb1a8f7a223fccdda Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 27 May 2016 18:20:08 -0700 Subject: [PATCH 01/15] Switch to libopencm3 branch with CAN support --- libopencm3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libopencm3 b/libopencm3 index 17f159d..c165345 160000 --- a/libopencm3 +++ b/libopencm3 @@ -1 +1 @@ -Subproject commit 17f159dec9a548d7e1984ed9fc3fea6d4eb776cf +Subproject commit c165345379d26084ae7ea38c1ee6d108dc503324 From 81d32e4126bffe0ad8820379dac93545388e60d4 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 27 May 2016 18:33:21 -0700 Subject: [PATCH 02/15] Add in CAN helpers --- src/CAN/can.c | 177 +++++++++++++++++++++++++++++++++++++++++++ src/CAN/can.h | 36 +++++++++ src/CAN/can_helper.h | 51 +++++++++++++ src/DAP42.c | 7 ++ src/Makefile | 1 + 5 files changed, 272 insertions(+) create mode 100644 src/CAN/can.c create mode 100644 src/CAN/can.h create mode 100644 src/CAN/can_helper.h diff --git a/src/CAN/can.c b/src/CAN/can.c new file mode 100644 index 0000000..ae4f774 --- /dev/null +++ b/src/CAN/can.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2015, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "config.h" +#include "can.h" + +#if CAN_RX_AVAILABLE + +static volatile CAN_Message can_rx_buffer[CAN_RX_BUFFER_SIZE]; +static uint8_t can_rx_head = 0; +static uint8_t can_rx_tail = 0; + +bool can_rx_buffer_empty(void) { + return can_rx_head == can_rx_tail; +} + +bool can_rx_buffer_full(void) { + return can_rx_head == ((can_rx_tail + 1) % CAN_RX_BUFFER_SIZE); +} + +static volatile const CAN_Message* can_rx_buffer_peek(void) { + return &can_rx_buffer[can_rx_head]; +} + +static void can_rx_buffer_pop(void) { + can_rx_head = (can_rx_head + 1) % CAN_RX_BUFFER_SIZE; +} + +static volatile CAN_Message* can_rx_buffer_tail(void) { + return &can_rx_buffer[can_rx_tail]; +} + +static void can_rx_buffer_extend(void) { + can_rx_tail = (can_rx_tail + 1) % CAN_RX_BUFFER_SIZE; +} + +void can_rx_buffer_put(const CAN_Message* msg) { + memcpy((void*)&can_rx_buffer[can_rx_tail], (const void*)msg, sizeof(CAN_Message)); + can_rx_tail = (can_rx_tail + 1) % CAN_RX_BUFFER_SIZE; +} + +void can_rx_buffer_get(CAN_Message* msg) { + memcpy((void*)msg, (const void*)&can_rx_buffer[can_rx_head], sizeof(CAN_Message)); + can_rx_head = (can_rx_head + 1) % CAN_RX_BUFFER_SIZE; +} + +bool can_setup(uint32_t baudrate) { + /* Enable CAN clock */ + rcc_periph_clock_enable(RCC_CAN); + + /* Setup CANRX */ + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); + gpio_set_af(GPIOB, GPIO_AF4, GPIO8); + +#if CAN_TX_AVAILABLE + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); + gpio_set_af(GPIOB, GPIO_AF4, GPIO9); +#endif + + /* Set appropriate bit timing */ + uint32_t sjw = CAN_BTR_SJW_1TQ; + uint32_t ts1; + uint32_t ts2; + uint32_t brp; + + if (baudrate == 1000000) { + brp = 3; + ts1 = CAN_BTR_TS1_11TQ; + ts2 = CAN_BTR_TS2_4TQ; + } else if (baudrate == 500000) { + brp = 6; + ts1 = CAN_BTR_TS1_11TQ; + ts2 = CAN_BTR_TS2_4TQ; + } else if (baudrate == 250000) { + brp = 12; + ts1 = CAN_BTR_TS1_11TQ; + ts2 = CAN_BTR_TS2_4TQ; + } else if (baudrate == 125000) { + brp = 24; + ts1 = CAN_BTR_TS1_11TQ; + ts2 = CAN_BTR_TS2_4TQ; + } else if (baudrate == 100000) { + brp = 30; + ts1 = CAN_BTR_TS1_11TQ; + ts2 = CAN_BTR_TS2_4TQ; + } else { + return false; + } + + can_reset(CAN); + + /* CAN cell init. */ + if (can_init(CAN, + false, /* TTCM: Time triggered comm mode? */ + true, /* ABOM: Automatic bus-off management? */ + false, /* AWUM: Automatic wakeup mode? */ + false, /* NART: No automatic retransmission? */ + true, /* RFLM: Receive FIFO locked mode? */ + false, /* TXFP: Transmit FIFO priority? */ + sjw, + ts1, + ts2, + brp,/* BRP+1: Baud rate prescaler */ + false,/* loopback mode */ + true))/* silent mode */ + { + return false; + } + + /* CAN filter 0 init. */ + can_filter_id_mask_32bit_init(CAN, + 0, /* Filter ID */ + 0, /* CAN ID */ + 0, /* CAN ID mask */ + 0, /* FIFO assignment (here: FIFO0) */ + true); /* Enable the filter. */ + + /* Enable CAN RX interrupt. */ + //can_enable_irq(CAN, CAN_IER_FMPIE0); + + //nvic_enable_irq(NVIC_CEC_CAN_IRQ); + + return true; +} + +bool can_read(CAN_Message* msg) { + bool success = false; + + uint8_t fifo = 0xFF; + if ((CAN_RF0R(CAN) & CAN_RF0R_FMP0_MASK) != 0) { + fifo = 0; + } else if ((CAN_RF1R(CAN) & CAN_RF1R_FMP1_MASK) != 0) { + fifo = 1; + } + + if (fifo != 0xFF) { + uint32_t fmi; + bool ext, rtr; + can_receive(CAN, fifo, true, &msg->id, &ext, &rtr, &fmi, &msg->len, msg->data); + + msg->format = ext ? CANExtended : CANStandard; + msg->type = rtr ? CANRemote : CANData; + success = true; + } + + return success; +} + + +/* +void cec_can_isr(void) { + +} +*/ + +#endif diff --git a/src/CAN/can.h b/src/CAN/can.h new file mode 100644 index 0000000..25479fd --- /dev/null +++ b/src/CAN/can.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CAN_H +#define CAN_H + +#include "can_helper.h" + +#define CAN_RX_BUFFER_SIZE 16 + +extern bool can_setup(uint32_t baudrate); +extern bool can_read(CAN_Message* msg); + +extern bool can_rx_buffer_empty(void); +extern bool can_rx_buffer_full(void); +extern void can_rx_buffer_put(const CAN_Message* msg); +extern void can_rx_buffer_get(CAN_Message* msg); + +//extern void cec_can_isr(void); + +#endif diff --git a/src/CAN/can_helper.h b/src/CAN/can_helper.h new file mode 100644 index 0000000..36a0d0e --- /dev/null +++ b/src/CAN/can_helper.h @@ -0,0 +1,51 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 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. + */ +#ifndef MBED_CAN_HELPER_H +#define MBED_CAN_HELPER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum CANFormat { + CANStandard = 0, + CANExtended = 1, + CANAny = 2 +}; +typedef enum CANFormat CANFormat; + +enum CANType { + CANData = 0, + CANRemote = 1 +}; +typedef enum CANType CANType; + +struct CAN_Message { + uint32_t id; // 29 bit identifier + uint8_t data[8]; // Data field + uint8_t len; // Length of data field in bytes + CANFormat format; // 0 - STANDARD, 1- EXTENDED IDENTIFIER + CANType type; // 0 - DATA FRAME, 1 - REMOTE FRAME +}; +typedef struct CAN_Message CAN_Message; + +#ifdef __cplusplus +}; +#endif + +#endif // MBED_CAN_HELPER_H diff --git a/src/DAP42.c b/src/DAP42.c index 48b54d2..89917b5 100644 --- a/src/DAP42.c +++ b/src/DAP42.c @@ -34,6 +34,8 @@ #include "DAP/CMSIS_DAP_hal.h" #include "DFU/DFU.h" +#include "CAN/can.h" + #include "tick.h" #include "retarget.h" #include "console.h" @@ -119,6 +121,10 @@ int main(void) { dfu_setup(usbd_dev, &on_dfu_request); } + if (CAN_RX_AVAILABLE) { + //can_setup(500000); + } + tick_start(); /* Enable the watchdog to enable DFU recovery from bad firmware images */ @@ -137,6 +143,7 @@ int main(void) { vcdc_app_update(); } + // Handle DAP bool dap_active = DAP_app_update(); if (dap_active) { diff --git a/src/Makefile b/src/Makefile index 13a87c1..c33d4e8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -66,6 +66,7 @@ SRCS := $(wildcard *.c) SRCS += $(wildcard DAP/*.c) SRCS += $(wildcard USB/*.c) SRCS += $(wildcard DFU/*.c) +SRCS += $(wildcard CAN/*.c) SRCS += $(wildcard $(TARGET_COMMON_DIR)/*.c) SRCS += $(wildcard $(TARGET_COMMON_DIR)/DAP/*.c) SRCS += $(wildcard $(TARGET_COMMON_DIR)/USB/*.c) From 86176fccc4bf64f7abd6f1674cfe3c21fdf0e650 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 28 May 2016 12:38:18 -0700 Subject: [PATCH 03/15] Add basic RX-only slcan implementation at 500k --- src/DAP42.c | 28 +++++++++++++++++++++++++++- src/retarget.c | 16 ++++++++++++++++ src/retarget.h | 2 ++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/DAP42.c b/src/DAP42.c index 89917b5..30d2330 100644 --- a/src/DAP42.c +++ b/src/DAP42.c @@ -122,7 +122,7 @@ int main(void) { } if (CAN_RX_AVAILABLE) { - //can_setup(500000); + can_setup(500000); } tick_start(); @@ -140,6 +140,32 @@ int main(void) { } if (VCDC_AVAILABLE) { + if (CAN_RX_AVAILABLE) { + CAN_Message msg; + bool read = false; + while (can_read(&msg)) { + read = true; + if (msg.format == CANStandard) { + print(msg.type == CANData ? "t" : "r"); + print_hex_nibble((uint8_t)(msg.id >> 8)); + print_hex_byte((uint8_t)(msg.id & 0xFF)); + putchar('0' + msg.len); + } else { + print(msg.type == CANData ? "T" : "R"); + print_hex(msg.id); + putchar('0' + msg.len); + } + uint8_t i = 0; + for (i=0; i < msg.len; i++) { + print_hex_byte(msg.data[i]); + } + putchar('\r'); + } + + if (read) { + fflush(stdout); + } + } vcdc_app_update(); } diff --git a/src/retarget.c b/src/retarget.c index b98b2d4..b8ae3e8 100644 --- a/src/retarget.c +++ b/src/retarget.c @@ -65,6 +65,22 @@ int _write(int file, char *ptr, int len) { #endif +void print_hex_nibble(uint8_t x) { + uint8_t nibble = x & 0x0F; + char nibble_char; + if (nibble < 10) { + nibble_char = '0' + nibble; + } else { + nibble_char = 'A' + (nibble - 10); + } + putchar(nibble_char); +} + +void print_hex_byte(uint8_t x) { + print_hex_nibble(x >> 4); + print_hex_nibble(x); +} + void print_hex(uint32_t x) { uint8_t i; for (i=8; i > 0; i--) { diff --git a/src/retarget.h b/src/retarget.h index 2117a48..5cd624f 100644 --- a/src/retarget.h +++ b/src/retarget.h @@ -28,6 +28,8 @@ extern void retarget(int file, uint32_t usart); extern int _write(int file, char *ptr, int len); extern void print_hex(uint32_t x); +extern void print_hex_nibble(uint8_t x); +extern void print_hex_byte(uint8_t x); extern void print(const char* s); extern void println(const char* s); From 4c551c84adbc128392fa48fcebc42b200ec31f4c Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Mon, 30 May 2016 10:57:53 -0700 Subject: [PATCH 04/15] Restructure for future CAN interrupt handler --- src/CAN/can.c | 83 ++++++++++++++++++++++++++++++-------------- src/CAN/can.h | 6 ++-- src/CAN/can_helper.h | 9 +++++ src/DAP42.c | 2 +- 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/CAN/can.c b/src/CAN/can.c index ae4f774..c0d71d4 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -65,19 +66,7 @@ void can_rx_buffer_get(CAN_Message* msg) { can_rx_head = (can_rx_head + 1) % CAN_RX_BUFFER_SIZE; } -bool can_setup(uint32_t baudrate) { - /* Enable CAN clock */ - rcc_periph_clock_enable(RCC_CAN); - - /* Setup CANRX */ - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); - gpio_set_af(GPIOB, GPIO_AF4, GPIO8); - -#if CAN_TX_AVAILABLE - gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); - gpio_set_af(GPIOB, GPIO_AF4, GPIO9); -#endif - +bool can_reconfigure(uint32_t baudrate, CanMode mode) { /* Set appropriate bit timing */ uint32_t sjw = CAN_BTR_SJW_1TQ; uint32_t ts1; @@ -110,6 +99,13 @@ bool can_setup(uint32_t baudrate) { can_reset(CAN); + bool loopback = (mode == MODE_TEST_LOCAL || mode == MODE_TEST_SILENT); + bool silent = (mode == MODE_SILENT || mode == MODE_TEST_SILENT); + + if (mode == MODE_TEST_GLOBAL) { + return false; + } + /* CAN cell init. */ if (can_init(CAN, false, /* TTCM: Time triggered comm mode? */ @@ -122,26 +118,43 @@ bool can_setup(uint32_t baudrate) { ts1, ts2, brp,/* BRP+1: Baud rate prescaler */ - false,/* loopback mode */ - true))/* silent mode */ + loopback,/* loopback mode */ + silent))/* silent mode */ { return false; } - /* CAN filter 0 init. */ - can_filter_id_mask_32bit_init(CAN, - 0, /* Filter ID */ - 0, /* CAN ID */ - 0, /* CAN ID mask */ - 0, /* FIFO assignment (here: FIFO0) */ - true); /* Enable the filter. */ + return true; +} - /* Enable CAN RX interrupt. */ - //can_enable_irq(CAN, CAN_IER_FMPIE0); +bool can_setup(uint32_t baudrate, CanMode mode) { + /* Enable CAN clock */ + rcc_periph_clock_enable(RCC_CAN); - //nvic_enable_irq(NVIC_CEC_CAN_IRQ); + /* Setup CANRX */ + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); + gpio_set_af(GPIOB, GPIO_AF4, GPIO8); - return true; +#if CAN_TX_AVAILABLE + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); + gpio_set_af(GPIOB, GPIO_AF4, GPIO9); +#endif + + if (can_reconfigure(baudrate, mode)) { + /* CAN filter 0 init. */ + can_filter_id_mask_32bit_init(CAN, + 0, /* Filter ID */ + 0, /* CAN ID */ + 0, /* CAN ID mask */ + 0, /* FIFO assignment (here: FIFO0) */ + true); /* Enable the filter. */ + /* Enable CAN RX interrupt. */ + //can_enable_irq(CAN, CAN_IER_FMPIE0); + //nvic_enable_irq(NVIC_CEC_CAN_IRQ); + return true; + } + + return false; } bool can_read(CAN_Message* msg) { @@ -167,10 +180,26 @@ bool can_read(CAN_Message* msg) { return success; } +bool can_read_buffer(CAN_Message* msg) { + bool success = false; + if (!can_rx_buffer_empty()) { + can_rx_buffer_get(msg); + success = true; + } + + return success; +} /* void cec_can_isr(void) { - + while (!can_rx_buffer_full()) { + CAN_Message msg; + bool read = can_read(&msg); + if (!read) { + break; + } + can_rx_buffer_put(&msg); + } } */ diff --git a/src/CAN/can.h b/src/CAN/can.h index 25479fd..f1c1ebe 100644 --- a/src/CAN/can.h +++ b/src/CAN/can.h @@ -23,14 +23,14 @@ #define CAN_RX_BUFFER_SIZE 16 -extern bool can_setup(uint32_t baudrate); +extern bool can_setup(uint32_t baudrate, CanMode mode); +extern bool can_reconfigure(uint32_t baudrate, CanMode mode); extern bool can_read(CAN_Message* msg); +extern bool can_read_buffer(CAN_Message* msg); extern bool can_rx_buffer_empty(void); extern bool can_rx_buffer_full(void); extern void can_rx_buffer_put(const CAN_Message* msg); extern void can_rx_buffer_get(CAN_Message* msg); -//extern void cec_can_isr(void); - #endif diff --git a/src/CAN/can_helper.h b/src/CAN/can_helper.h index 36a0d0e..0268c84 100644 --- a/src/CAN/can_helper.h +++ b/src/CAN/can_helper.h @@ -44,6 +44,15 @@ struct CAN_Message { }; typedef struct CAN_Message CAN_Message; +typedef enum { + MODE_RESET, + MODE_NORMAL, + MODE_SILENT, + MODE_TEST_LOCAL, + MODE_TEST_GLOBAL, + MODE_TEST_SILENT +} CanMode; + #ifdef __cplusplus }; #endif diff --git a/src/DAP42.c b/src/DAP42.c index 30d2330..647295e 100644 --- a/src/DAP42.c +++ b/src/DAP42.c @@ -122,7 +122,7 @@ int main(void) { } if (CAN_RX_AVAILABLE) { - can_setup(500000); + can_setup(500000, MODE_SILENT); } tick_start(); From 4b9771ee44eed4197d8493a2cc6313f0c4bc2ac9 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Thu, 2 Jun 2016 20:35:36 -0700 Subject: [PATCH 05/15] Add initial slcan parser Implement slcan parser in `slcan.c/h` Add `can_write` function Remove non-implementable `MODE_TEST_GLOBAL` Reformat call to `can_init` for readability --- src/CAN/can.c | 42 +++--- src/CAN/can.h | 2 + src/CAN/can_helper.h | 1 - src/CAN/slcan.c | 312 +++++++++++++++++++++++++++++++++++++++++++ src/CAN/slcan.h | 34 +++++ src/DAP42.c | 36 +---- src/USB/vcdc.c | 47 +++++++ src/USB/vcdc.h | 7 + 8 files changed, 433 insertions(+), 48 deletions(-) create mode 100644 src/CAN/slcan.c create mode 100644 src/CAN/slcan.h diff --git a/src/CAN/can.c b/src/CAN/can.c index c0d71d4..17b5ceb 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -67,6 +67,13 @@ void can_rx_buffer_get(CAN_Message* msg) { } bool can_reconfigure(uint32_t baudrate, CanMode mode) { + can_reset(CAN); + + if (mode == MODE_RESET) { + // Just stop after resetting the CAN controller. + return true; + } + /* Set appropriate bit timing */ uint32_t sjw = CAN_BTR_SJW_1TQ; uint32_t ts1; @@ -97,29 +104,22 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { return false; } - can_reset(CAN); - bool loopback = (mode == MODE_TEST_LOCAL || mode == MODE_TEST_SILENT); bool silent = (mode == MODE_SILENT || mode == MODE_TEST_SILENT); - if (mode == MODE_TEST_GLOBAL) { - return false; - } + bool TTCM = false; /* TTCM: Time triggered comm mode? */ + bool ABOM = true; /* ABOM: Automatic bus-off management? */ + bool AWUM = false; /* AWUM: Automatic wakeup mode? */ + bool NART = false; /* NART: No automatic retransmission? */ + bool RFLM = true; /* RFLM: Receive FIFO locked mode? */ + bool TXFP = false; /* TXFP: Transmit FIFO priority? */ /* CAN cell init. */ - if (can_init(CAN, - false, /* TTCM: Time triggered comm mode? */ - true, /* ABOM: Automatic bus-off management? */ - false, /* AWUM: Automatic wakeup mode? */ - false, /* NART: No automatic retransmission? */ - true, /* RFLM: Receive FIFO locked mode? */ - false, /* TXFP: Transmit FIFO priority? */ - sjw, - ts1, - ts2, - brp,/* BRP+1: Baud rate prescaler */ - loopback,/* loopback mode */ - silent))/* silent mode */ + if (can_init(CAN, TTCM, ABOM, AWUM, NART, RFLM, TXFP, + sjw, ts1, ts2, + brp, /* BRP+1: Baud rate prescaler */ + loopback, + silent) != 0) { return false; } @@ -190,6 +190,12 @@ bool can_read_buffer(CAN_Message* msg) { return success; } +bool can_write(CAN_Message* msg) { + bool ext = msg->format == CANExtended; + bool rtr = msg->type == CANRemote; + return (can_transmit(CAN, msg->id, ext, rtr, msg->len, msg->data) != -1); +} + /* void cec_can_isr(void) { while (!can_rx_buffer_full()) { diff --git a/src/CAN/can.h b/src/CAN/can.h index f1c1ebe..a58612f 100644 --- a/src/CAN/can.h +++ b/src/CAN/can.h @@ -28,6 +28,8 @@ extern bool can_reconfigure(uint32_t baudrate, CanMode mode); extern bool can_read(CAN_Message* msg); extern bool can_read_buffer(CAN_Message* msg); +extern bool can_write(CAN_Message* msg); + extern bool can_rx_buffer_empty(void); extern bool can_rx_buffer_full(void); extern void can_rx_buffer_put(const CAN_Message* msg); diff --git a/src/CAN/can_helper.h b/src/CAN/can_helper.h index 0268c84..e6e1852 100644 --- a/src/CAN/can_helper.h +++ b/src/CAN/can_helper.h @@ -49,7 +49,6 @@ typedef enum { MODE_NORMAL, MODE_SILENT, MODE_TEST_LOCAL, - MODE_TEST_GLOBAL, MODE_TEST_SILENT } CanMode; diff --git a/src/CAN/slcan.c b/src/CAN/slcan.c new file mode 100644 index 0000000..55d8956 --- /dev/null +++ b/src/CAN/slcan.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "USB/vcdc.h" +#include "retarget.h" +#include "slcan.h" + +CanMode slcan_mode; +uint32_t slcan_baudrate; + +static bool parse_hex_digits(const char* input, uint8_t num_digits, uint32_t* value_out) { + bool success = true; + uint32_t value = 0; + + uint8_t i; + for (i=0; i < num_digits; i++) { + uint32_t nibble = 0; + if (input[i] >= '0' && input[i] <= '9') { + nibble = 0x0 + (input[i] - '0'); + } else if (input[i] >= 'a' && input[i] <= 'f') { + nibble = 0xA + (input[i] - 'a'); + } else if (input[i] >= 'A' && input[i] <= 'F') { + nibble = 0xA + (input[i] - 'A'); + } else { + success = false; + break; + } + uint8_t offset = 4*(num_digits-i-1); + value |= (nibble << offset); + } + + if (success) { + *value_out = value; + } + + return success; +} + +static bool parse_hex_values(const char* input, uint8_t num_values, uint8_t* values_out) { + uint8_t i; + for (i=0; i < num_values; i++) { + uint32_t value; + if (parse_hex_digits(input, 2, &value)) { + values_out[i] = (uint8_t)value; + } else { + return false; + } + input += 2; + } + + return true; +} + +static bool parse_dec_digit(const char* input, uint8_t* value_out) { + if (input[0] >= '0' && input[0] <= '9') { + *value_out = 0 + (input[0] - '0'); + return true; + } else { + return false; + } +} + +static bool slcan_process_config_command(const char* command, size_t len) { + bool success = false; + if (len != 1 && command[0] != 'S') { + return false; + } else if (command[0] == 'S' && len != 2) { + return false; + } + + if (slcan_mode != MODE_RESET && command[0] != 'C') { + return false; + } else if (command[0] == 'C' && slcan_mode == MODE_RESET) { + return false; + } + + switch (command[0]) { + case 'S': { + switch (command[1]) { + case '3': + slcan_baudrate = 100000; + success = true; + break; + case '4': + slcan_baudrate = 125000; + success = true; + break; + case '5': + slcan_baudrate = 250000; + success = true; + break; + case '6': + slcan_baudrate = 500000; + success = true; + break; + case '8': + slcan_baudrate = 1000000; + success = true; + break; + default: + success = false; + break; + } + break; + } + case 'O': { + slcan_mode = MODE_NORMAL; + success = can_reconfigure(slcan_baudrate, slcan_mode); + break; + } + case 'L': { + slcan_mode = MODE_SILENT; + success = can_reconfigure(slcan_baudrate, slcan_mode); + break; + } + case 'l': { + slcan_mode = MODE_TEST_SILENT; + success = can_reconfigure(slcan_baudrate, slcan_mode); + break; + } + case 'C': { + slcan_mode = MODE_RESET; + success = can_reconfigure(slcan_baudrate, slcan_mode); + break; + } + default: { + success = false; + break; + } + } + + return success; +} + +static bool slcan_process_transmit_command(const char* command, size_t len) { + bool success = false; + + if (slcan_mode == MODE_RESET || slcan_mode == MODE_SILENT) { + return false; + } + + bool valid_message = false; + CAN_Message msg; + if (command[0] == 't' || command[0] == 'T') { + msg.type = CANData; + msg.format = (command[0] == 't') ? CANStandard : CANExtended; + size_t id_len = msg.format == CANStandard ? 3 : 8; + if ((len >= id_len + 2) && + parse_hex_digits(&command[1], id_len, &msg.id) && + parse_dec_digit(&command[id_len + 1], &msg.len)) { + if ((len == id_len + 2 + 2*msg.len) && + (msg.len <= 8) && + parse_hex_values(&command[id_len + 2], msg.len, msg.data)) { + valid_message = true; + } + } + } else if (command[0] == 'r' || command[0] == 'R') { + msg.type = CANRemote; + msg.format = (command[0] == 'r') ? CANStandard : CANExtended; + size_t id_len = msg.format == CANStandard ? 3 : 8; + if ((len == id_len + 2) && + parse_hex_digits(&command[1], id_len, &msg.id) && + parse_dec_digit(&command[id_len + 1], &msg.len)) { + if (msg.len <= 8) { + valid_message = true; + } + } + } + + if (valid_message) { + success = can_write(&msg); + } + + return success; +} + +bool slcan_exec_command(const char* command, size_t len) { + bool success = false; + + switch (command[0]) { + // Configuration commands + case 'S': + case 'O': + case 'L': + case 'l': + case 'C': { + success = slcan_process_config_command(command, len); + break; + } + // Transmission commands + case 't': + case 'T': + case 'r': + case 'R': { + success = slcan_process_transmit_command(command, len); + break; + } + default: { + success = false; + break; + } + } + + return success; +} + +bool slcan_output_messages(void) { + if (slcan_mode == MODE_RESET) { + return false; + } + bool read = false; + CAN_Message msg; + while (can_read(&msg)) { + read = true; + if (msg.format == CANStandard) { + vcdc_print(msg.type == CANData ? "t" : "r"); + vcdc_print_hex_nibble((uint8_t)(msg.id >> 8)); + vcdc_print_hex_byte((uint8_t)(msg.id & 0xFF)); + vcdc_putchar('0' + msg.len); + } else { + vcdc_print(msg.type == CANData ? "T" : "R"); + vcdc_print_hex(msg.id); + vcdc_putchar('0' + msg.len); + } + uint8_t i = 0; + for (i=0; i < msg.len; i++) { + vcdc_print_hex_byte(msg.data[i]); + } + vcdc_putchar('\r'); + } + + return read; +} + +void slcan_app_setup(uint32_t baudrate, CanMode mode) { + slcan_mode = mode; + slcan_baudrate = baudrate; + can_setup(baudrate, mode); +} + +bool slcan_app_update(void) { + bool active = false; + if (slcan_output_messages()) { + active = true; + } + + static char command_buffer[SLCAN_MAX_MESSAGE_LEN+1]; + static size_t command_len = 0; + static bool overflow = false; + + while (command_len < sizeof(command_buffer)) { + if (vcdc_recv_buffered((uint8_t*)&command_buffer[command_len], 1)) { + if (command_buffer[command_len] == '\r') { + if (overflow) { + // Reject the command and exit overflow + command_len = 0; + overflow = false; + vcdc_putchar(SLCAN_ERROR); + active = true; + } else { + // Process the command + command_buffer[command_len] = '\0'; + bool success = slcan_exec_command(command_buffer, command_len); + command_len = 0; + if (success) { + vcdc_putchar(SLCAN_OK); + } else { + vcdc_putchar(SLCAN_ERROR); + } + active = true; + } + break; + } else if (command_buffer[command_len] == '\n' && command_len == 0) { + // Ignore line-feed after carriage-return + continue; + } else if (overflow) { + // Ignore everything until the end of the command + continue; + } else { + // Add a character to the command + command_len++; + } + } else { + break; + } + } + + if (command_len >= sizeof(command_buffer)) { + overflow = true; + command_len = 0; + } + + return active; +} diff --git a/src/CAN/slcan.h b/src/CAN/slcan.h new file mode 100644 index 0000000..6903bd5 --- /dev/null +++ b/src/CAN/slcan.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SLCAN_H_INCLUDED +#define SLCAN_H_INCLUDED + +#include "can.h" + +#define SLCAN_MAX_MESSAGE_LEN 27 + +#define SLCAN_OK '\r' +#define SLCAN_ERROR '\a' + +extern bool slcan_output_messages(void); +extern bool slcan_exec_command(const char* command, size_t len); +extern void slcan_app_setup(uint32_t baudrate, CanMode mode); +extern bool slcan_app_update(void); + +#endif diff --git a/src/DAP42.c b/src/DAP42.c index 647295e..16dd542 100644 --- a/src/DAP42.c +++ b/src/DAP42.c @@ -34,7 +34,7 @@ #include "DAP/CMSIS_DAP_hal.h" #include "DFU/DFU.h" -#include "CAN/can.h" +#include "CAN/slcan.h" #include "tick.h" #include "retarget.h" @@ -121,8 +121,8 @@ int main(void) { dfu_setup(usbd_dev, &on_dfu_request); } - if (CAN_RX_AVAILABLE) { - can_setup(500000, MODE_SILENT); + if (CAN_RX_AVAILABLE && VCDC_AVAILABLE) { + slcan_app_setup(500000, MODE_RESET); } tick_start(); @@ -139,33 +139,11 @@ int main(void) { cdc_uart_app_update(); } + if (CAN_RX_AVAILABLE && VCDC_AVAILABLE) { + slcan_app_update(); + } + if (VCDC_AVAILABLE) { - if (CAN_RX_AVAILABLE) { - CAN_Message msg; - bool read = false; - while (can_read(&msg)) { - read = true; - if (msg.format == CANStandard) { - print(msg.type == CANData ? "t" : "r"); - print_hex_nibble((uint8_t)(msg.id >> 8)); - print_hex_byte((uint8_t)(msg.id & 0xFF)); - putchar('0' + msg.len); - } else { - print(msg.type == CANData ? "T" : "R"); - print_hex(msg.id); - putchar('0' + msg.len); - } - uint8_t i = 0; - for (i=0; i < msg.len; i++) { - print_hex_byte(msg.data[i]); - } - putchar('\r'); - } - - if (read) { - fflush(stdout); - } - } vcdc_app_update(); } diff --git a/src/USB/vcdc.c b/src/USB/vcdc.c index ed362aa..3a572dc 100644 --- a/src/USB/vcdc.c +++ b/src/USB/vcdc.c @@ -249,4 +249,51 @@ bool vcdc_app_update(void) { return active; } +void vcdc_putchar(const char c) { + if (!vcdc_tx_buffer_full()) { + vcdc_tx_buffer_put(c); + } +} + +void vcdc_print(const char* s) { + while (*s != '\0') { + vcdc_putchar(*s++); + } +} + +void vcdc_println(const char* s) { + while (*s != '\0') { + vcdc_putchar(*s++); + } + vcdc_putchar('\r'); + vcdc_putchar('\n'); +} + +void vcdc_print_hex_nibble(uint8_t x) { + uint8_t nibble = x & 0x0F; + char nibble_char; + if (nibble < 10) { + nibble_char = '0' + nibble; + } else { + nibble_char = 'A' + (nibble - 10); + } + vcdc_putchar(nibble_char); +} + +void vcdc_print_hex_byte(uint8_t x) { + vcdc_print_hex_nibble(x >> 4); + vcdc_print_hex_nibble(x); +} + +void vcdc_print_hex(uint32_t x) { + vcdc_print_hex_nibble((uint8_t)(x >> 28)); + vcdc_print_hex_nibble((uint8_t)(x >> 24)); + vcdc_print_hex_nibble((uint8_t)(x >> 20)); + vcdc_print_hex_nibble((uint8_t)(x >> 16)); + vcdc_print_hex_nibble((uint8_t)(x >> 12)); + vcdc_print_hex_nibble((uint8_t)(x >> 8)); + vcdc_print_hex_nibble((uint8_t)(x >> 4)); + vcdc_print_hex_nibble((uint8_t)(x >> 0)); +} + #endif diff --git a/src/USB/vcdc.h b/src/USB/vcdc.h index 1e9cb95..a4622f4 100644 --- a/src/USB/vcdc.h +++ b/src/USB/vcdc.h @@ -31,4 +31,11 @@ extern bool vcdc_app_update(void); extern size_t vcdc_recv_buffered(uint8_t* data, size_t max_bytes); extern size_t vcdc_send_buffered(const uint8_t* data, size_t num_bytes); +extern void vcdc_putchar(const char c); +extern void vcdc_print(const char* s); +extern void vcdc_println(const char* s); +extern void vcdc_print_hex(uint32_t x); +extern void vcdc_print_hex_byte(uint8_t x); +extern void vcdc_print_hex_nibble(uint8_t x); + #endif From 6175347cdbf79c48f461a174ed93a4438eee4f17 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 3 Jun 2016 01:14:02 -0700 Subject: [PATCH 06/15] Move CAN filter setup into can_reconfigure Move default accept-all filter into can_reconfigure to simplify changing modes for now. --- src/CAN/can.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/CAN/can.c b/src/CAN/can.c index 17b5ceb..a89adb8 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -119,11 +119,16 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { sjw, ts1, ts2, brp, /* BRP+1: Baud rate prescaler */ loopback, - silent) != 0) - { + silent) != 0) { return false; + } else { + can_filter_id_mask_32bit_init(CAN, + 0, /* Filter ID */ + 0, /* CAN ID */ + 0, /* CAN ID mask */ + 0, /* FIFO assignment (here: FIFO0) */ + true); /* Enable the filter. */ } - return true; } @@ -140,21 +145,7 @@ bool can_setup(uint32_t baudrate, CanMode mode) { gpio_set_af(GPIOB, GPIO_AF4, GPIO9); #endif - if (can_reconfigure(baudrate, mode)) { - /* CAN filter 0 init. */ - can_filter_id_mask_32bit_init(CAN, - 0, /* Filter ID */ - 0, /* CAN ID */ - 0, /* CAN ID mask */ - 0, /* FIFO assignment (here: FIFO0) */ - true); /* Enable the filter. */ - /* Enable CAN RX interrupt. */ - //can_enable_irq(CAN, CAN_IER_FMPIE0); - //nvic_enable_irq(NVIC_CEC_CAN_IRQ); - return true; - } - - return false; + return can_reconfigure(baudrate, mode); } bool can_read(CAN_Message* msg) { From 95c81dc031df1f544908f042206f72bb6330d4f8 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 25 Mar 2017 15:39:43 -0700 Subject: [PATCH 07/15] Add USBtinViewer compatibility commands Add minimal support for some SLCAN queries that USBtinViewer makes when connecting. Process and respond to commands before sending encoded CAN messages --- src/CAN/slcan.c | 116 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 7 deletions(-) diff --git a/src/CAN/slcan.c b/src/CAN/slcan.c index 55d8956..cc17b26 100644 --- a/src/CAN/slcan.c +++ b/src/CAN/slcan.c @@ -80,9 +80,21 @@ static bool parse_dec_digit(const char* input, uint8_t* value_out) { static bool slcan_process_config_command(const char* command, size_t len) { bool success = false; - if (len != 1 && command[0] != 'S') { - return false; - } else if (command[0] == 'S' && len != 2) { + + // Validate command length + if (command[0] == 'M' || command[0] == 'm') { + if (len != 9) { + return false; + } + } else if (command[0] == 's') { + if (!((len == 5) || (len == 7))) { + return false; + } + } else if (command[0] == 'S' || command[0] == 'Z') { + if (len != 2) { + return false; + } + } else if (len != 1) { return false; } @@ -141,6 +153,23 @@ static bool slcan_process_config_command(const char* command, size_t len) { success = can_reconfigure(slcan_baudrate, slcan_mode); break; } + // Dummy commands for compatibility + case 's': { + // TODO: implement direct BTR control + success = true; + break; + } + case 'M': + case 'm': { + // TODO: implement filtering + success = true; + break; + } + case 'Z': { + // TODO: implement timestamping + success = true; + break; + } default: { success = false; break; @@ -186,12 +215,70 @@ static bool slcan_process_transmit_command(const char* command, size_t len) { } if (valid_message) { + if (command[0] == 'r' || command[0] == 't') { + vcdc_putchar('z'); + } else { + vcdc_putchar('Z'); + } success = can_write(&msg); } return success; } +static bool slcan_process_diagnostic_command(const char* command, size_t len) { + bool success = false; + + // Validate command length + if (command[0] == 'W') { + if (len != 5) { + return false; + } + } else { + if (len != 1) { + return false; + } + } + + switch (command[0]) { + case 'V': { + // Hardware and firmware version + success = true; + vcdc_print("V1111"); + break; + } + case 'v': { + // Firmware version + success = true; + vcdc_print("v11"); + break; + } + case 'N': { + // Serial number + success = true; + vcdc_print("C254"); + break; + } + case 'F': { + // Internal status register + success = true; + vcdc_print("F00"); + break; + } + case 'W': { + // Ignore the MCP2515 register write + success = true; + break; + } + default: { + success = false; + break; + } + } + + return success; +} + bool slcan_exec_command(const char* command, size_t len) { bool success = false; @@ -201,7 +288,11 @@ bool slcan_exec_command(const char* command, size_t len) { case 'O': case 'L': case 'l': - case 'C': { + case 'C': + case 's': + case 'M': + case 'm': + case 'Z': { success = slcan_process_config_command(command, len); break; } @@ -213,6 +304,15 @@ bool slcan_exec_command(const char* command, size_t len) { success = slcan_process_transmit_command(command, len); break; } + // Diagnostic commands + case 'V': + case 'v': + case 'N': + case 'F': + case 'W': { + success = slcan_process_diagnostic_command(command, len); + break; + } default: { success = false; break; @@ -258,9 +358,6 @@ void slcan_app_setup(uint32_t baudrate, CanMode mode) { bool slcan_app_update(void) { bool active = false; - if (slcan_output_messages()) { - active = true; - } static char command_buffer[SLCAN_MAX_MESSAGE_LEN+1]; static size_t command_len = 0; @@ -308,5 +405,10 @@ bool slcan_app_update(void) { command_len = 0; } + if (slcan_output_messages()) { + active = true; + } + + return active; } From 7abca076bd72cb301761595514612960039f310b Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Tue, 11 Apr 2017 23:01:06 -0700 Subject: [PATCH 08/15] Use the ISR-driven CAN RX buffer for SLCAN --- src/CAN/can.c | 15 +++++++++++---- src/CAN/slcan.c | 2 +- src/stm32f042/brain3.3/config.h | 1 + src/stm32f042/dap42/config.h | 1 + src/stm32f042/kitchen42/config.h | 1 + 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/CAN/can.c b/src/CAN/can.c index a89adb8..a5cc42b 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -29,8 +29,8 @@ #if CAN_RX_AVAILABLE static volatile CAN_Message can_rx_buffer[CAN_RX_BUFFER_SIZE]; -static uint8_t can_rx_head = 0; -static uint8_t can_rx_tail = 0; +static volatile uint8_t can_rx_head = 0; +static volatile uint8_t can_rx_tail = 0; bool can_rx_buffer_empty(void) { return can_rx_head == can_rx_tail; @@ -67,6 +67,8 @@ void can_rx_buffer_get(CAN_Message* msg) { } bool can_reconfigure(uint32_t baudrate, CanMode mode) { + nvic_disable_irq(CAN_NVIC_LINE); + can_disable_irq(CAN, CAN_IER_FMPIE0 | CAN_IER_FMPIE1); can_reset(CAN); if (mode == MODE_RESET) { @@ -129,6 +131,9 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { 0, /* FIFO assignment (here: FIFO0) */ true); /* Enable the filter. */ } + + can_enable_irq(CAN, CAN_IER_FMPIE0 | CAN_IER_FMPIE1); + nvic_enable_irq(CAN_NVIC_LINE); return true; } @@ -148,6 +153,8 @@ bool can_setup(uint32_t baudrate, CanMode mode) { return can_reconfigure(baudrate, mode); } + + bool can_read(CAN_Message* msg) { bool success = false; @@ -187,7 +194,7 @@ bool can_write(CAN_Message* msg) { return (can_transmit(CAN, msg->id, ext, rtr, msg->len, msg->data) != -1); } -/* + void cec_can_isr(void) { while (!can_rx_buffer_full()) { CAN_Message msg; @@ -198,6 +205,6 @@ void cec_can_isr(void) { can_rx_buffer_put(&msg); } } -*/ + #endif diff --git a/src/CAN/slcan.c b/src/CAN/slcan.c index cc17b26..3a84bf1 100644 --- a/src/CAN/slcan.c +++ b/src/CAN/slcan.c @@ -328,7 +328,7 @@ bool slcan_output_messages(void) { } bool read = false; CAN_Message msg; - while (can_read(&msg)) { + while (can_read_buffer(&msg)) { read = true; if (msg.format == CANStandard) { vcdc_print(msg.type == CANData ? "t" : "r"); diff --git a/src/stm32f042/brain3.3/config.h b/src/stm32f042/brain3.3/config.h index 4a3d8a1..10d1a5d 100644 --- a/src/stm32f042/brain3.3/config.h +++ b/src/stm32f042/brain3.3/config.h @@ -24,6 +24,7 @@ #define CAN_RX_AVAILABLE 1 #define CAN_TX_AVAILABLE 0 +#define CAN_NVIC_LINE NVIC_CEC_CAN_IRQ #define VCDC_AVAILABLE 0 #define VCDC_TX_BUFFER_SIZE 256 diff --git a/src/stm32f042/dap42/config.h b/src/stm32f042/dap42/config.h index 227e461..081d519 100644 --- a/src/stm32f042/dap42/config.h +++ b/src/stm32f042/dap42/config.h @@ -24,6 +24,7 @@ #define CAN_RX_AVAILABLE 1 #define CAN_TX_AVAILABLE 0 +#define CAN_NVIC_LINE NVIC_CEC_CAN_IRQ #define VCDC_AVAILABLE 0 #define VCDC_TX_BUFFER_SIZE 256 diff --git a/src/stm32f042/kitchen42/config.h b/src/stm32f042/kitchen42/config.h index 26da08a..308d50b 100644 --- a/src/stm32f042/kitchen42/config.h +++ b/src/stm32f042/kitchen42/config.h @@ -24,6 +24,7 @@ #define CAN_RX_AVAILABLE 1 #define CAN_TX_AVAILABLE 1 +#define CAN_NVIC_LINE NVIC_CEC_CAN_IRQ #define VCDC_AVAILABLE 1 #define VCDC_TX_BUFFER_SIZE 256 From 80ae349d8ce57578045867cbfcbd5da282271fa4 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Tue, 11 Apr 2017 23:02:11 -0700 Subject: [PATCH 09/15] Enable SLCAN on BRAINv3.33 boards --- src/stm32f042/brain3.3/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stm32f042/brain3.3/config.h b/src/stm32f042/brain3.3/config.h index 10d1a5d..fd20906 100644 --- a/src/stm32f042/brain3.3/config.h +++ b/src/stm32f042/brain3.3/config.h @@ -26,7 +26,7 @@ #define CAN_TX_AVAILABLE 0 #define CAN_NVIC_LINE NVIC_CEC_CAN_IRQ -#define VCDC_AVAILABLE 0 +#define VCDC_AVAILABLE 1 #define VCDC_TX_BUFFER_SIZE 256 #define VCDC_RX_BUFFER_SIZE 256 From 2279fcde603205c92f6b04068a2a56c75aaa15db Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Wed, 12 Apr 2017 21:10:40 -0700 Subject: [PATCH 10/15] Fix CAN FIFO dequeuing bug that generated duplicates Releasing the current CAN message from the hardware FIFO takes time. While the message is being released, the FIFO depth is not decremented. This caused the ISR to repeatedly read the same message from the FIFO. can_read now checks the RFOM bit to determine if there are actual messages in the fifo or if it's just a previously read message that has not yet been released. can_read also now only uses one FIFO for simplicity, since the second FIFO was not being configured anyways. --- src/CAN/can.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/CAN/can.c b/src/CAN/can.c index a5cc42b..295b2e6 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -68,7 +68,7 @@ void can_rx_buffer_get(CAN_Message* msg) { bool can_reconfigure(uint32_t baudrate, CanMode mode) { nvic_disable_irq(CAN_NVIC_LINE); - can_disable_irq(CAN, CAN_IER_FMPIE0 | CAN_IER_FMPIE1); + can_disable_irq(CAN, CAN_IER_FMPIE0); can_reset(CAN); if (mode == MODE_RESET) { @@ -132,7 +132,7 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { true); /* Enable the filter. */ } - can_enable_irq(CAN, CAN_IER_FMPIE0 | CAN_IER_FMPIE1); + can_enable_irq(CAN, CAN_IER_FMPIE0); nvic_enable_irq(CAN_NVIC_LINE); return true; } @@ -158,18 +158,19 @@ bool can_setup(uint32_t baudrate, CanMode mode) { bool can_read(CAN_Message* msg) { bool success = false; - uint8_t fifo = 0xFF; - if ((CAN_RF0R(CAN) & CAN_RF0R_FMP0_MASK) != 0) { - fifo = 0; - } else if ((CAN_RF1R(CAN) & CAN_RF1R_FMP1_MASK) != 0) { - fifo = 1; + uint8_t fifo_depth = (CAN_RF0R(CAN) & CAN_RF0R_FMP0_MASK); + // Account for one fifo entry possibly going away + if (CAN_RF0R(CAN) & CAN_RF0R_RFOM0) { + fifo_depth = fifo_depth > 0 ? (fifo_depth - 1) : 0; } - if (fifo != 0xFF) { + if (fifo_depth > 0) { + // Wait for the previous message to be released + while (CAN_RF0R(CAN) & CAN_RF0R_RFOM0); + uint32_t fmi; bool ext, rtr; - can_receive(CAN, fifo, true, &msg->id, &ext, &rtr, &fmi, &msg->len, msg->data); - + can_receive(CAN, 0, true, &msg->id, &ext, &rtr, &fmi, &msg->len, msg->data); msg->format = ext ? CANExtended : CANStandard; msg->type = rtr ? CANRemote : CANData; success = true; @@ -198,11 +199,11 @@ bool can_write(CAN_Message* msg) { void cec_can_isr(void) { while (!can_rx_buffer_full()) { CAN_Message msg; - bool read = can_read(&msg); - if (!read) { + if (can_read(&msg)) { + can_rx_buffer_put(&msg); + } else { break; } - can_rx_buffer_put(&msg); } } From c4c9a1a3988392993ee859a28e5b5136f09c4468 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 28 Apr 2017 00:56:15 -0700 Subject: [PATCH 11/15] Improve SLCAN stability when the UART is active slcan_output_messages now stops formatting messages where there is no more room in the virtual CDC-ACM output buffer. Redo the vcdc circular buffers with unmasked head and tail counters so that it's easier to calculate the amount of space used/available. Redo the CAN RX circular buffer with unmasked head and tail counters so that one more message slot can be used compared to before. Rewrite the CAN ISR to avoid starving the MCU when message processing slows down and the RX buffer fills up. It now disables the ISR on overflow so that the main loop always has a chance to run. --- src/CAN/can.c | 66 ++++++++++++++++++++++++++++++++----------------- src/CAN/can.h | 2 ++ src/CAN/slcan.c | 50 ++++++++++++++++++++++++++++--------- src/USB/vcdc.c | 24 ++++++++++-------- src/USB/vcdc.h | 2 ++ 5 files changed, 99 insertions(+), 45 deletions(-) diff --git a/src/CAN/can.c b/src/CAN/can.c index 295b2e6..67ac00c 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -37,33 +37,43 @@ bool can_rx_buffer_empty(void) { } bool can_rx_buffer_full(void) { - return can_rx_head == ((can_rx_tail + 1) % CAN_RX_BUFFER_SIZE); + return (uint8_t)(can_rx_tail - can_rx_head) == CAN_RX_BUFFER_SIZE; } -static volatile const CAN_Message* can_rx_buffer_peek(void) { - return &can_rx_buffer[can_rx_head]; +CAN_Message* can_rx_buffer_peek(void) { + if (!can_rx_buffer_empty()) { + return (CAN_Message*)(&can_rx_buffer[(can_rx_head % CAN_RX_BUFFER_SIZE)]); + } else { + return NULL; + } } -static void can_rx_buffer_pop(void) { - can_rx_head = (can_rx_head + 1) % CAN_RX_BUFFER_SIZE; +void can_rx_buffer_pop(void) { + can_rx_head++; + + // Re-enable the ISR since we made space + nvic_enable_irq(CAN_NVIC_LINE); } -static volatile CAN_Message* can_rx_buffer_tail(void) { - return &can_rx_buffer[can_rx_tail]; +static CAN_Message* can_rx_buffer_tail(void) { + return (CAN_Message*)&can_rx_buffer[(can_rx_tail % CAN_RX_BUFFER_SIZE)]; } static void can_rx_buffer_extend(void) { - can_rx_tail = (can_rx_tail + 1) % CAN_RX_BUFFER_SIZE; + can_rx_tail++; } void can_rx_buffer_put(const CAN_Message* msg) { - memcpy((void*)&can_rx_buffer[can_rx_tail], (const void*)msg, sizeof(CAN_Message)); - can_rx_tail = (can_rx_tail + 1) % CAN_RX_BUFFER_SIZE; + memcpy((void*)&can_rx_buffer[(can_rx_tail % CAN_RX_BUFFER_SIZE)], (const void*)msg, sizeof(CAN_Message)); + can_rx_tail++; } void can_rx_buffer_get(CAN_Message* msg) { - memcpy((void*)msg, (const void*)&can_rx_buffer[can_rx_head], sizeof(CAN_Message)); - can_rx_head = (can_rx_head + 1) % CAN_RX_BUFFER_SIZE; + memcpy((void*)msg, (const void*)&can_rx_buffer[(can_rx_head % CAN_RX_BUFFER_SIZE)], sizeof(CAN_Message)); + can_rx_head++; + + // Re-enable the ISR since we made space + nvic_enable_irq(CAN_NVIC_LINE); } bool can_reconfigure(uint32_t baudrate, CanMode mode) { @@ -153,18 +163,20 @@ bool can_setup(uint32_t baudrate, CanMode mode) { return can_reconfigure(baudrate, mode); } - - -bool can_read(CAN_Message* msg) { - bool success = false; - +static uint8_t can_fifo_depth(void) { uint8_t fifo_depth = (CAN_RF0R(CAN) & CAN_RF0R_FMP0_MASK); // Account for one fifo entry possibly going away if (CAN_RF0R(CAN) & CAN_RF0R_RFOM0) { fifo_depth = fifo_depth > 0 ? (fifo_depth - 1) : 0; } - if (fifo_depth > 0) { + return fifo_depth; +} + +bool can_read(CAN_Message* msg) { + bool success = false; + + if (can_fifo_depth() > 0) { // Wait for the previous message to be released while (CAN_RF0R(CAN) & CAN_RF0R_RFOM0); @@ -195,16 +207,24 @@ bool can_write(CAN_Message* msg) { return (can_transmit(CAN, msg->id, ext, rtr, msg->len, msg->data) != -1); } - void cec_can_isr(void) { - while (!can_rx_buffer_full()) { - CAN_Message msg; - if (can_read(&msg)) { - can_rx_buffer_put(&msg); + uint8_t messages_queued = 0; + uint8_t fifo_depth = can_fifo_depth(); + while (!can_rx_buffer_full() && messages_queued < fifo_depth) { + CAN_Message* msg = can_rx_buffer_tail(); + if (can_read(msg)) { + can_rx_buffer_extend(); + messages_queued++; } else { break; } } + + // If the software buffer is full, disable the ISR so that + // the main loop can drain the buffer over USB. + if (messages_queued == 0) { + nvic_disable_irq(CAN_NVIC_LINE); + } } diff --git a/src/CAN/can.h b/src/CAN/can.h index a58612f..ed9e6e7 100644 --- a/src/CAN/can.h +++ b/src/CAN/can.h @@ -34,5 +34,7 @@ extern bool can_rx_buffer_empty(void); extern bool can_rx_buffer_full(void); extern void can_rx_buffer_put(const CAN_Message* msg); extern void can_rx_buffer_get(CAN_Message* msg); +extern CAN_Message* can_rx_buffer_peek(void); +extern void can_rx_buffer_pop(void); #endif diff --git a/src/CAN/slcan.c b/src/CAN/slcan.c index 3a84bf1..7d97fdd 100644 --- a/src/CAN/slcan.c +++ b/src/CAN/slcan.c @@ -322,29 +322,55 @@ bool slcan_exec_command(const char* command, size_t len) { return success; } +static size_t slcan_calc_message_length(const CAN_Message* msg) { + size_t len; + if (msg->format == CANStandard) { + len = 1 + 3 + 1 + (2 * msg->len) + 1; + } else { + len = 1 + 8 + 1 + (2 * msg->len) + 1; + } + + return len; +} + bool slcan_output_messages(void) { if (slcan_mode == MODE_RESET) { return false; } bool read = false; - CAN_Message msg; - while (can_read_buffer(&msg)) { + + size_t avail_buf_len = vcdc_send_buffer_space(); + while (!can_rx_buffer_empty()) { + // Examine the current message without dequeuing it + CAN_Message* msg = can_rx_buffer_peek(); + + // Stop processing messages if there's no more room + size_t msg_len = slcan_calc_message_length(msg); + if (msg_len > avail_buf_len) { + break; + } + read = true; - if (msg.format == CANStandard) { - vcdc_print(msg.type == CANData ? "t" : "r"); - vcdc_print_hex_nibble((uint8_t)(msg.id >> 8)); - vcdc_print_hex_byte((uint8_t)(msg.id & 0xFF)); - vcdc_putchar('0' + msg.len); + if (msg->format == CANStandard) { + vcdc_print(msg->type == CANData ? "t" : "r"); + vcdc_print_hex_nibble((uint8_t)(msg->id >> 8)); + vcdc_print_hex_byte((uint8_t)(msg->id & 0xFF)); + vcdc_putchar('0' + msg->len); } else { - vcdc_print(msg.type == CANData ? "T" : "R"); - vcdc_print_hex(msg.id); - vcdc_putchar('0' + msg.len); + vcdc_print(msg->type == CANData ? "T" : "R"); + vcdc_print_hex(msg->id); + vcdc_putchar('0' + msg->len); } uint8_t i = 0; - for (i=0; i < msg.len; i++) { - vcdc_print_hex_byte(msg.data[i]); + for (i=0; i < msg->len; i++) { + vcdc_print_hex_byte(msg->data[i]); } vcdc_putchar('\r'); + + avail_buf_len -= msg_len; + + // Release the message now that it's been processed + can_rx_buffer_pop(); } return read; diff --git a/src/USB/vcdc.c b/src/USB/vcdc.c index 3a572dc..fa5a319 100644 --- a/src/USB/vcdc.c +++ b/src/USB/vcdc.c @@ -70,17 +70,17 @@ static bool vcdc_tx_buffer_empty(void) { } static bool vcdc_tx_buffer_full(void) { - return vcdc_tx_head == ((vcdc_tx_tail + 1) % VCDC_TX_BUFFER_SIZE); + return (uint16_t)(vcdc_tx_tail - vcdc_tx_head) == VCDC_TX_BUFFER_SIZE; } static void vcdc_tx_buffer_put(uint8_t data) { - vcdc_tx_buffer[vcdc_tx_tail] = data; - vcdc_tx_tail = (vcdc_tx_tail + 1) % VCDC_TX_BUFFER_SIZE; + vcdc_tx_buffer[vcdc_tx_tail % VCDC_TX_BUFFER_SIZE] = data; + vcdc_tx_tail++; } static uint8_t vcdc_tx_buffer_get(void) { - uint8_t data = vcdc_tx_buffer[vcdc_tx_head]; - vcdc_tx_head = (vcdc_tx_head + 1) % VCDC_TX_BUFFER_SIZE; + uint8_t data = vcdc_tx_buffer[vcdc_tx_head % VCDC_TX_BUFFER_SIZE]; + vcdc_tx_head++; return data; } @@ -89,17 +89,17 @@ static bool vcdc_rx_buffer_empty(void) { } static bool vcdc_rx_buffer_full(void) { - return vcdc_rx_head == ((vcdc_rx_tail + 1) % VCDC_RX_BUFFER_SIZE); + return (uint16_t)(vcdc_rx_tail - vcdc_rx_head) == VCDC_RX_BUFFER_SIZE; } static void vcdc_rx_buffer_put(uint8_t data) { - vcdc_rx_buffer[vcdc_rx_tail] = data; - vcdc_rx_tail = (vcdc_rx_tail + 1) % VCDC_RX_BUFFER_SIZE; + vcdc_rx_buffer[vcdc_rx_tail % VCDC_RX_BUFFER_SIZE] = data; + vcdc_rx_tail++; } static uint8_t vcdc_rx_buffer_get(void) { - uint8_t data = vcdc_rx_buffer[vcdc_rx_head]; - vcdc_rx_head = (vcdc_rx_head + 1) % VCDC_RX_BUFFER_SIZE; + uint8_t data = vcdc_rx_buffer[vcdc_rx_head % VCDC_RX_BUFFER_SIZE]; + vcdc_rx_head++; return data; } @@ -121,6 +121,10 @@ size_t vcdc_send_buffered(const uint8_t* data, size_t num_bytes) { return bytes_queued; } +size_t vcdc_send_buffer_space(void) { + return VCDC_TX_BUFFER_SIZE - (uint16_t)(vcdc_tx_tail - vcdc_tx_head); +} + /* User callbacks */ static GenericCallback vcdc_rx_callback = NULL; static GenericCallback vcdc_tx_callback = NULL; diff --git a/src/USB/vcdc.h b/src/USB/vcdc.h index a4622f4..451ab83 100644 --- a/src/USB/vcdc.h +++ b/src/USB/vcdc.h @@ -31,6 +31,8 @@ extern bool vcdc_app_update(void); extern size_t vcdc_recv_buffered(uint8_t* data, size_t max_bytes); extern size_t vcdc_send_buffered(const uint8_t* data, size_t num_bytes); +extern size_t vcdc_send_buffer_space(void); + extern void vcdc_putchar(const char c); extern void vcdc_print(const char* s); extern void vcdc_println(const char* s); From 38961c6c9a63fadd94174649766f78ca8be699a2 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 28 Apr 2017 01:00:54 -0700 Subject: [PATCH 12/15] Add missing CAN ISR definition to DAP42K6U config --- src/stm32f042/dap42k6u/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stm32f042/dap42k6u/config.h b/src/stm32f042/dap42k6u/config.h index 816382a..3e48d64 100644 --- a/src/stm32f042/dap42k6u/config.h +++ b/src/stm32f042/dap42k6u/config.h @@ -24,6 +24,7 @@ #define CAN_RX_AVAILABLE 1 #define CAN_TX_AVAILABLE 0 +#define CAN_NVIC_LINE NVIC_CEC_CAN_IRQ #define VCDC_AVAILABLE 0 #define VCDC_TX_BUFFER_SIZE 256 From 488dcdb19b6c56891fdba19f18ba51a92e14a714 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 29 Apr 2017 13:27:02 -0700 Subject: [PATCH 13/15] Add static asserts to validate circular buffer sizes Circular buffers using unmasked indices have size restrictions: * The size must be an exact power of two * The size cannot be greater than half of the max value represented by the index type Buffers used to process data from USB out endpoints must also be big enough to hold at least one maximum size packet to prevent the flow control logic from NAK'ing all packets. --- src/CAN/can.c | 6 ++++++ src/USB/cdc.c | 3 +++ src/USB/vcdc.c | 13 +++++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/CAN/can.c b/src/CAN/can.c index 67ac00c..7332cf3 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -28,6 +28,12 @@ #if CAN_RX_AVAILABLE +#define IS_POW_OF_TWO(X) (((X) & ((X)-1)) == 0) +_Static_assert(IS_POW_OF_TWO(CAN_RX_BUFFER_SIZE), + "Unmasked circular buffer size must be a power of two"); +_Static_assert(CAN_RX_BUFFER_SIZE <= UINT8_MAX/2, + "Buffer size too big for unmasked circular buffer"); + static volatile CAN_Message can_rx_buffer[CAN_RX_BUFFER_SIZE]; static volatile uint8_t can_rx_head = 0; static volatile uint8_t can_rx_tail = 0; diff --git a/src/USB/cdc.c b/src/USB/cdc.c index 3bfa9b3..b5a7335 100644 --- a/src/USB/cdc.c +++ b/src/USB/cdc.c @@ -30,6 +30,9 @@ #if CDC_AVAILABLE +_Static_assert((CONSOLE_TX_BUFFER_SIZE >= USB_CDC_MAX_PACKET_SIZE), + "TX buffer too small"); + /* Descriptors */ const struct cdc_acm_functional_descriptors cdc_acm_functional_descriptors = { .header = { diff --git a/src/USB/vcdc.c b/src/USB/vcdc.c index fa5a319..d31f8e4 100644 --- a/src/USB/vcdc.c +++ b/src/USB/vcdc.c @@ -65,6 +65,19 @@ static uint16_t vcdc_tx_tail = 0; static uint16_t vcdc_rx_head = 0; static uint16_t vcdc_rx_tail = 0; +_Static_assert((VCDC_RX_BUFFER_SIZE >= USB_VCDC_MAX_PACKET_SIZE), + "RX buffer too small"); + +#define IS_POW_OF_TWO(X) (((X) & ((X)-1)) == 0) +_Static_assert(IS_POW_OF_TWO(VCDC_RX_BUFFER_SIZE), + "Unmasked circular buffer size must be a power of two"); +_Static_assert(IS_POW_OF_TWO(VCDC_TX_BUFFER_SIZE), + "Unmasked circular buffer size must be a power of two"); +_Static_assert(VCDC_TX_BUFFER_SIZE <= UINT16_MAX/2, + "Buffer size too big for unmasked circular buffer"); +_Static_assert(VCDC_RX_BUFFER_SIZE <= UINT16_MAX/2, + "Buffer size too big for unmasked circular buffer"); + static bool vcdc_tx_buffer_empty(void) { return vcdc_tx_head == vcdc_tx_tail; } From 9612bc80eb0181b035b52d459f173c3c00a87c20 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 13 May 2017 10:37:22 -0700 Subject: [PATCH 14/15] Update USB PMA check to take CAN into account --- src/USB/composite_usb_conf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/USB/composite_usb_conf.c b/src/USB/composite_usb_conf.c index 36738de..41383c9 100644 --- a/src/USB/composite_usb_conf.c +++ b/src/USB/composite_usb_conf.c @@ -66,7 +66,13 @@ _Static_assert((1 + NUM_OUT_ENDPOINTS <= 8), "Too many OUT endpoints for USB cor + CDC_PMA_USAGE \ + VCDC_PMA_USAGE) -_Static_assert((TOTAL_PMA_USAGE <= USB_PMA_SIZE), "USB packet memory area overallocated"); +#if CAN_RX_AVAILABLE && VCDC_AVAILABLE +#define MAX_USB_PMA_SIZE USB_PMA_SIZE_WITH_CAN +#else +#define MAX_USB_PMA_SIZE USB_PMA_SIZE +#endif + +_Static_assert((TOTAL_PMA_USAGE <= MAX_USB_PMA_SIZE), "USB packet memory area overallocated"); static const struct usb_device_descriptor dev = { .bLength = USB_DT_DEVICE_SIZE, From 6311fd2e493db22c2e85f04dd17374b205507926 Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Fri, 25 Aug 2017 09:04:23 -0700 Subject: [PATCH 15/15] Update to the latest version of locm3 can: use CAN1 instead of CAN, update parameters for can_receive console: replace usart_get_interrupt_source with usart_get_flag stlinkv2-1: replace RCC_CFGR_MCO_HSECLK with RCC_CFGR_MCO_HSE --- libopencm3 | 2 +- src/CAN/can.c | 22 +++++++++++----------- src/console.c | 2 +- src/stm32f103/stlinkv2-1/target.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libopencm3 b/libopencm3 index c165345..b0e050d 160000 --- a/libopencm3 +++ b/libopencm3 @@ -1 +1 @@ -Subproject commit c165345379d26084ae7ea38c1ee6d108dc503324 +Subproject commit b0e050d10d12c42be031c34822117cfd3c5a0ea7 diff --git a/src/CAN/can.c b/src/CAN/can.c index 7332cf3..dfc2070 100644 --- a/src/CAN/can.c +++ b/src/CAN/can.c @@ -84,8 +84,8 @@ void can_rx_buffer_get(CAN_Message* msg) { bool can_reconfigure(uint32_t baudrate, CanMode mode) { nvic_disable_irq(CAN_NVIC_LINE); - can_disable_irq(CAN, CAN_IER_FMPIE0); - can_reset(CAN); + can_disable_irq(CAN1, CAN_IER_FMPIE0); + can_reset(CAN1); if (mode == MODE_RESET) { // Just stop after resetting the CAN controller. @@ -133,14 +133,14 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { bool TXFP = false; /* TXFP: Transmit FIFO priority? */ /* CAN cell init. */ - if (can_init(CAN, TTCM, ABOM, AWUM, NART, RFLM, TXFP, + if (can_init(CAN1, TTCM, ABOM, AWUM, NART, RFLM, TXFP, sjw, ts1, ts2, brp, /* BRP+1: Baud rate prescaler */ loopback, silent) != 0) { return false; } else { - can_filter_id_mask_32bit_init(CAN, + can_filter_id_mask_32bit_init(CAN1, 0, /* Filter ID */ 0, /* CAN ID */ 0, /* CAN ID mask */ @@ -148,7 +148,7 @@ bool can_reconfigure(uint32_t baudrate, CanMode mode) { true); /* Enable the filter. */ } - can_enable_irq(CAN, CAN_IER_FMPIE0); + can_enable_irq(CAN1, CAN_IER_FMPIE0); nvic_enable_irq(CAN_NVIC_LINE); return true; } @@ -170,9 +170,9 @@ bool can_setup(uint32_t baudrate, CanMode mode) { } static uint8_t can_fifo_depth(void) { - uint8_t fifo_depth = (CAN_RF0R(CAN) & CAN_RF0R_FMP0_MASK); + uint8_t fifo_depth = (CAN_RF0R(CAN1) & CAN_RF0R_FMP0_MASK); // Account for one fifo entry possibly going away - if (CAN_RF0R(CAN) & CAN_RF0R_RFOM0) { + if (CAN_RF0R(CAN1) & CAN_RF0R_RFOM0) { fifo_depth = fifo_depth > 0 ? (fifo_depth - 1) : 0; } @@ -184,11 +184,11 @@ bool can_read(CAN_Message* msg) { if (can_fifo_depth() > 0) { // Wait for the previous message to be released - while (CAN_RF0R(CAN) & CAN_RF0R_RFOM0); + while (CAN_RF0R(CAN1) & CAN_RF0R_RFOM0); - uint32_t fmi; + uint8_t fmi; bool ext, rtr; - can_receive(CAN, 0, true, &msg->id, &ext, &rtr, &fmi, &msg->len, msg->data); + can_receive(CAN1, 0, true, &msg->id, &ext, &rtr, &fmi, &msg->len, msg->data, NULL); msg->format = ext ? CANExtended : CANStandard; msg->type = rtr ? CANRemote : CANData; success = true; @@ -210,7 +210,7 @@ bool can_read_buffer(CAN_Message* msg) { bool can_write(CAN_Message* msg) { bool ext = msg->format == CANExtended; bool rtr = msg->type == CANRemote; - return (can_transmit(CAN, msg->id, ext, rtr, msg->len, msg->data) != -1); + return (can_transmit(CAN1, msg->id, ext, rtr, msg->len, msg->data) != -1); } void cec_can_isr(void) { diff --git a/src/console.c b/src/console.c index c143e1b..39c3592 100644 --- a/src/console.c +++ b/src/console.c @@ -205,7 +205,7 @@ uint8_t console_recv_blocking(void) { } void CONSOLE_USART_IRQ_NAME(void) { - if (usart_get_interrupt_source(CONSOLE_USART, USART_SR_TXE)) { + if (usart_get_flag(CONSOLE_USART, USART_SR_TXE)) { if (!console_tx_buffer_empty()) { usart_word_t buffered_byte = console_tx_buffer_get(); usart_send(CONSOLE_USART, buffered_byte); diff --git a/src/stm32f103/stlinkv2-1/target.c b/src/stm32f103/stlinkv2-1/target.c index 04c4a2f..f3f9dce 100644 --- a/src/stm32f103/stlinkv2-1/target.c +++ b/src/stm32f103/stlinkv2-1/target.c @@ -67,7 +67,7 @@ void gpio_setup(void) { gpio_clear(GPIOB, GPIO15); /* Enable MCO output */ - rcc_set_mco(RCC_CFGR_MCO_HSECLK); + rcc_set_mco(RCC_CFGR_MCO_HSE); gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8); /* Setup LEDs as open-drain outputs */