From b485617e1578ade7cb02e65a674d56315098b18c Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 13 Jan 2017 16:22:34 +0100 Subject: o Adding a CAN example. --- apps/CMakeLists.txt | 1 + apps/can1/CMakeLists.txt | 25 +++ apps/can1/can1.cpp | 400 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 apps/can1/CMakeLists.txt create mode 100644 apps/can1/can1.cpp diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index f5fe450..ae23c31 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(can1) add_subdirectory(cpp1) add_subdirectory(dma1) add_subdirectory(os1) diff --git a/apps/can1/CMakeLists.txt b/apps/can1/CMakeLists.txt new file mode 100644 index 0000000..20ebd0d --- /dev/null +++ b/apps/can1/CMakeLists.txt @@ -0,0 +1,25 @@ +add_executable(can1.elf can1.cpp + ${PLAYGROUND_DIR}/src/init_low.s ${PLAYGROUND_DIR}/src/init_high.cpp ${PLAYGROUND_DIR}/include/init_high.h + ${PLAYGROUND_DIR}/include/playground.h + ${PLAYGROUND_DIR}/src/debug.cpp ${PLAYGROUND_DIR}/include/debug.h + ${PLAYGROUND_DIR}/include/stm32f10x_conf.h + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport/core_cm3.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/misc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_can.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c + ) +target_link_libraries(can1.elf tinyprintf) + +target_include_directories(can1.elf PUBLIC + ${PLAYGROUND_DIR}/include + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/inc) + +target_compile_definitions(can1.elf PUBLIC + ${STM32F10X_STDPERIPH_DEFINES}) + +set_target_properties(can1.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld") +add_extra_commands(can1.elf) diff --git a/apps/can1/can1.cpp b/apps/can1/can1.cpp new file mode 100644 index 0000000..d3ec6b1 --- /dev/null +++ b/apps/can1/can1.cpp @@ -0,0 +1,400 @@ +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "tinyprintf.h" +#include "playground.h" + +extern "C" +__attribute__((naked, used)) +void HardFault_Handler_C(uint32_t *hardfault_args) { + dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]); + dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]); + dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]); + dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]); + dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]); + dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]); + dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]); + dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]); + dbg_printf("\n"); + + halt(); +} + +__attribute__((used)) +size_t strlen(const char *s) { + size_t size = 0; + while (*s++ != '\0') size++; + return size; +} + +volatile uint8_t tx_ready = 0; + +class apb_1_tag { +public: + static const int bus_id = 1; +}; + +class apb_2_tag { +public: + static const int bus_id = 2; +}; + +class peripheral_usage_ref { +public: + virtual void enable() = 0; + + virtual void disable() = 0; +}; + +template +class peripheral_usage final : public peripheral_usage_ref { + +public: + peripheral_usage() : count(0) {} + + void enable() { + dbg_printf("enable: %d:%08" PRIx32 ", count=%d\n", apb_tag::bus_id, peripheral_id, count); + if (count == 0) { + do_enable(apb_tag{}); + } + count++; + } + + void disable() { + dbg_printf("disable: %d:%08" PRIx32 ", count=%d\n", apb_tag::bus_id, peripheral_id, count); + count--; + if (count == 0) { + do_disable(apb_tag{}); + } + } + +private: + static void do_enable(apb_1_tag) { + RCC_APB1PeriphClockCmd(peripheral_id, ENABLE); + + RCC_APB1PeriphResetCmd(peripheral_id, ENABLE); + RCC_APB1PeriphResetCmd(peripheral_id, DISABLE); + } + + static void do_disable(apb_1_tag) { + RCC_APB1PeriphClockCmd(peripheral_id, DISABLE); + } + + static void do_enable(apb_2_tag) { + RCC_APB2PeriphClockCmd(peripheral_id, ENABLE); + + RCC_APB2PeriphResetCmd(peripheral_id, ENABLE); + RCC_APB2PeriphResetCmd(peripheral_id, DISABLE); + } + + static void do_disable(apb_2_tag) { + RCC_APB2PeriphClockCmd(peripheral_id, DISABLE); + } + + int count; +}; + +peripheral_usage can1_peripheral; + +peripheral_usage gpioa_peripheral; +peripheral_usage afio_peripheral; + +GPIO_TypeDef *debug_gpio_block = GPIOA; +const uint16_t debug_pin_a = GPIO_Pin_2; +const uint16_t debug_pin_b = GPIO_Pin_3; +//const uint16_t debug_pin_2 = GPIO_Pin_2; + +CAN_TypeDef *can = CAN1; + +const uint16_t can_rx_pin = GPIO_Pin_11; +const uint16_t can_tx_pin = GPIO_Pin_12; + +bool debug_pins_init() { + gpioa_peripheral.enable(); + + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + + init.GPIO_Pin = debug_pin_a; + init.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(debug_gpio_block, &init); + + init.GPIO_Pin = debug_pin_b; + init.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(debug_gpio_block, &init); + +// init.GPIO_Pin = debug_pin_2; +// init.GPIO_Mode = GPIO_Mode_Out_PP; +// GPIO_Init(debug_gpio_block, &init); + + return true; +} + +bool can_init(peripheral_usage_ref &gpio_peripheral, peripheral_usage_ref &afio_peripheral, + peripheral_usage_ref &can_peripheral, GPIO_TypeDef *gpioBlock, + uint16_t rx_pin, uint16_t tx_pin) { + gpio_peripheral.enable(); + afio_peripheral.enable(); + + GPIO_InitTypeDef gpioInit; + gpioInit.GPIO_Pin = rx_pin; + gpioInit.GPIO_Mode = GPIO_Mode_IPU; + GPIO_Init(gpioBlock, &gpioInit); + + gpioInit.GPIO_Pin = tx_pin; + gpioInit.GPIO_Mode = GPIO_Mode_AF_PP; + gpioInit.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(gpioBlock, &gpioInit); + +// GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); + + can_peripheral.enable(); + + { + CAN_InitTypeDef init; + CAN_StructInit(&init); + + CAN_DeInit(can); + + init.CAN_TTCM = DISABLE; + init.CAN_ABOM = DISABLE; + init.CAN_AWUM = DISABLE; + init.CAN_NART = DISABLE; + init.CAN_RFLM = DISABLE; + init.CAN_TXFP = DISABLE; + init.CAN_Mode = CAN_Mode_Normal; +// init.CAN_Mode = CAN_Mode_LoopBack; + + init.CAN_SJW = CAN_SJW_1tq; + init.CAN_BS1 = CAN_BS1_3tq; + init.CAN_BS2 = CAN_BS2_5tq; + init.CAN_Prescaler = 64; + auto ret = CAN_Init(can, &init); + + if (ret != CAN_InitStatus_Success) { + return false; + } + + CAN_ITConfig(can, CAN_IT_TME | + CAN_IT_FMP0 | + CAN_IT_FF0 | + CAN_IT_FOV0 | + CAN_IT_FMP1 | + CAN_IT_FF1 | + CAN_IT_FOV1 | + CAN_IT_EWG | + CAN_IT_EPV | + CAN_IT_LEC | + CAN_IT_ERR | + CAN_IT_WKU | + CAN_IT_SLK, ENABLE); + } + + { + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); + + NVIC_InitTypeDef init{ + .NVIC_IRQChannel = 0, + .NVIC_IRQChannelPreemptionPriority = 0, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE + }; + + init.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; + NVIC_Init(&init); + NVIC_EnableIRQ(static_cast(init.NVIC_IRQChannel)); + + init.NVIC_IRQChannel = USB_HP_CAN1_TX_IRQn; + NVIC_Init(&init); + NVIC_EnableIRQ(static_cast(init.NVIC_IRQChannel)); + + init.NVIC_IRQChannel = CAN1_SCE_IRQn; + NVIC_Init(&init); + NVIC_EnableIRQ(static_cast(init.NVIC_IRQChannel)); + + init.NVIC_IRQChannel = CAN1_RX1_IRQn; + NVIC_Init(&init); + NVIC_EnableIRQ(static_cast(init.NVIC_IRQChannel)); + } + + return true; +} + +static volatile bool run = true; + +/** + * To set this flag, set a hbreak in gdb (hb main) and then set it to 1 (set variable is_client = 1). + */ +volatile int is_client = false; + +CanRxMsg msg; +volatile bool msg_valid = false; + +int main() { + SystemInit(); + + is_client = is_client != 0; + dbg_printf("can1: client=%d\n", is_client); + + init_printf(nullptr, dbg_putc); + + debug_pins_init(); + + if (!can_init(gpioa_peripheral, afio_peripheral, can1_peripheral, GPIOA, can_rx_pin, can_tx_pin)) { + dbg_printf("CAN init failed!"); + } + + for (int i = 0; i < 10; i++) { + GPIO_SetBits(GPIOA, debug_pin_a); + GPIO_ResetBits(GPIOA, debug_pin_a); + } + + if (!is_client) { + while (run) { + GPIO_SetBits(GPIOA, debug_pin_a); + GPIO_ResetBits(GPIOA, debug_pin_a); + + dbg_printf("CAN_TSR=%08" PRIx32 ", CAN_ESR=%08" PRIx32 "\n", can->TSR, can->ESR); + + CanTxMsg txMsg; + txMsg.StdId = 0x321; + txMsg.ExtId = 0x01; + txMsg.RTR = CAN_RTR_Data; + txMsg.IDE = CAN_Id_Extended; + txMsg.DLC = 8; + for (int i = 0; i < 8; i++) { + txMsg.Data[i] = static_cast(i + 1); + } + + CAN_Transmit(can, &txMsg); + run = false; + } + + for (int i = 0; i < 10; i++) { + dbg_printf("CAN_TSR=%08" PRIx32 ", CAN_ESR=%08" PRIx32 "\n", can->TSR, can->ESR); + } + } else { + CAN_FilterInitTypeDef init; + init.CAN_FilterNumber = 0; + init.CAN_FilterMode = CAN_FilterMode_IdMask; + init.CAN_FilterScale = CAN_FilterScale_32bit; + init.CAN_FilterIdHigh = 0x0000; + init.CAN_FilterIdLow = 0x0000; + init.CAN_FilterMaskIdHigh = 0x0000; + init.CAN_FilterMaskIdLow = 0x0000; + init.CAN_FilterFIFOAssignment = 0; + init.CAN_FilterActivation = ENABLE; + CAN_FilterInit(&init); + } + + if (!is_client) { + dbg_printf("Waiting ...\n"); + } + + run = true; + while (run) { + if (is_client) { +// dbg_printf("CAN_TSR=%08" PRIx32 ", CAN_ESR=%08" PRIx32 "\n", can->TSR, can->ESR); + + if (msg_valid) { + dbg_printf("Got message: StdId=%" PRIu32 + ", ExtId=%" PRIu32 + ", IDE=%d" + ", RTR=%d" + ", DLC=%d" + ", FMI=%d" + ", DATA=%08" PRIx32 "%08" PRIx32 "\n", + msg.StdId, msg.ExtId, (int) msg.IDE, (int) msg.RTR, (int) msg.DLC, (int) msg.FMI, + (uint32_t) (msg.Data[0] << 24 | msg.Data[1] << 16 | msg.Data[2] << 8 | msg.Data[3]), + (uint32_t) (msg.Data[4] << 24 | msg.Data[5] << 16 | msg.Data[6] << 8 | msg.Data[7])); + msg_valid = false; + } + } + } + + return 0; +} + +void on_intr(const char *function) { + dbg_printf("%s: CAN_TSR=%08" PRIx32 ", CAN_ESR=%08" PRIx32 "\n", function, can->TSR, can->ESR); + uint8_t tec = CAN_GetLSBTransmitErrorCounter(can); + uint8_t rec = CAN_GetReceiveErrorCounter(can); + dbg_printf("TEC: %d, REC: %d\n", tec, rec); + +#define check(flag) if(CAN_GetITStatus(can, flag)) { dbg_printf(#flag "\n"); CAN_ClearITPendingBit(can, flag); } + check(CAN_IT_TME); + check(CAN_IT_FMP0); + check(CAN_IT_FF0); + check(CAN_IT_FOV0); + check(CAN_IT_FMP1); + check(CAN_IT_FF1); + check(CAN_IT_FOV1); + check(CAN_IT_WKU); + check(CAN_IT_SLK); + check(CAN_IT_EWG); + check(CAN_IT_EPV); + check(CAN_IT_BOF); + check(CAN_IT_LEC); +#undef check + +#define check(flag) if (CAN_GetFlagStatus(can, flag) == SET) { dbg_printf(#flag "\n"); CAN_ClearFlag(can, flag); } + check(CAN_FLAG_EWG); + check(CAN_FLAG_EPV); + check(CAN_FLAG_BOF); + check(CAN_FLAG_RQCP0); + check(CAN_FLAG_RQCP1); + check(CAN_FLAG_RQCP2); + check(CAN_FLAG_FMP1); + check(CAN_FLAG_FF1); + check(CAN_FLAG_FOV1); + check(CAN_FLAG_FMP0); + check(CAN_FLAG_FF0); + check(CAN_FLAG_FOV0); + check(CAN_FLAG_WKU); + check(CAN_FLAG_SLAK); + check(CAN_FLAG_LEC); +#undef check +} + +extern "C" +void USB_HP_CAN1_TX_IRQHandler() { + GPIO_SetBits(GPIOA, debug_pin_b); + GPIO_ResetBits(GPIOA, debug_pin_b); + + on_intr(__FUNCTION__); +} + +extern "C" +void USB_LP_CAN1_RX0_IRQHandler() { + GPIO_SetBits(GPIOA, debug_pin_b); + GPIO_ResetBits(GPIOA, debug_pin_b); + + on_intr(__FUNCTION__); + + if (CAN_GetITStatus(can, CAN_IT_FMP0)) { + CAN_Receive(can, 0, &msg); + msg_valid = true; + CAN_ClearITPendingBit(can, CAN_IT_FMP0); + } +} + +extern "C" +void CAN1_RX1_IRQHandler() { + GPIO_SetBits(GPIOA, debug_pin_b); + GPIO_ResetBits(GPIOA, debug_pin_b); + + on_intr(__FUNCTION__); +} + +extern "C" +void CAN1_SCE_IRQHandler() { + GPIO_SetBits(GPIOA, debug_pin_b); + GPIO_ResetBits(GPIOA, debug_pin_b); + + on_intr(__FUNCTION__); +} -- cgit v1.2.3