diff --git a/CMakeLists.txt b/CMakeLists.txt index 5de44fc..3f8fc86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${COMMON_LINKER_FLAGS}") project(bobbycar-controller-firmware ASM C CXX) -add_definitions(-DUSE_HAL_DRIVER -DSTM32F103xE) +add_definitions(-DUSE_HAL_DRIVER -DSTM32F103xE -DFEATURE_CAN) include_directories( . @@ -54,6 +54,7 @@ add_executable(firmware.elf STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc.c STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c + STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c bobbycar-foc-model/BLDC_controller.h bobbycar-foc-model/BLDC_controller.c @@ -68,6 +69,8 @@ add_executable(firmware.elf config.h defines.h main.cpp + can.c + can_feedc0de.cpp ) add_custom_command(OUTPUT firmware.hex diff --git a/can.c b/can.c new file mode 100644 index 0000000..581c42b --- /dev/null +++ b/can.c @@ -0,0 +1,369 @@ +#include "stm32f1xx_hal.h" + +#include "can_feedc0de.h" +#include "can.h" + +/* Definition for CANx clock resources */ +#define CANx CAN1 +#define CANx_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE() +#define CANx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define CANx_FORCE_RESET() __HAL_RCC_CAN1_FORCE_RESET() +#define CANx_RELEASE_RESET() __HAL_RCC_CAN1_RELEASE_RESET() + +/* Definition for CANx Pins */ +#define CANx_TX_PIN GPIO_PIN_9 +#define CANx_TX_GPIO_PORT GPIOB +#define CANx_RX_PIN GPIO_PIN_8 +#define CANx_RX_GPIO_PORT GPIOB + +/* Definition for CANx AFIO Remap */ +#define CANx_AFIO_REMAP_CLK_ENABLE() __HAL_RCC_AFIO_CLK_ENABLE() +#define CANx_AFIO_REMAP_RX_TX_PIN() __HAL_AFIO_REMAP_CAN1_2() + +/* Definition for CAN's NVIC */ +#define CANx_RX_IRQn USB_LP_CAN1_RX0_IRQn +#define CANx_RX_IRQHandler USB_LP_CAN1_RX0_IRQHandler +#define CANx_TX_IRQn USB_HP_CAN1_TX_IRQn +#define CANx_TX_IRQHandler USB_HP_CAN1_TX_IRQHandler + + +/** + ****************************************************************************** + * @file CAN/CAN_Networking/Src/main.c + * @author MCD Application Team + * @brief This example shows how to configure the CAN peripheral + * to send and receive CAN frames in normal mode. The sent frames + * are used to control Leds by pressing KEY Push Button. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2016 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Private variables ---------------------------------------------------------*/ +uint8_t ubKeyNumber = 0x0; +CAN_HandleTypeDef CanHandle; +CAN_TxHeaderTypeDef TxHeader; +CAN_RxHeaderTypeDef RxHeader; +uint8_t TxData[8]; +uint8_t RxData[8]; +uint32_t TxMailbox; + +/* Private function prototypes -----------------------------------------------*/ +static void __NO_RETURN Error_Handler(void); +static void CAN_MspInit(CAN_HandleTypeDef *hcan); +static void CAN_MspDeInit(CAN_HandleTypeDef *hcan); +static void CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan); +static void CAN_TxMailboxCompleteCallback(CAN_HandleTypeDef *hcan); + +/* Private functions ---------------------------------------------------------*/ + +static uint32_t len_to_dlc(uint8_t len) +{ + uint32_t len_u32 = len; + + if (len_u32 <= 8) + return len_u32; + + // CAN-FD-only lengths currently not supported + Error_Handler(); +} + +static uint8_t dlc_to_len(uint32_t dlc) +{ + // Check if DLC valid + if (dlc & ~0xFu) + Error_Handler(); + + // CAN-FD-only lengths currently not supported + if (dlc > 8) + Error_Handler(); + + return dlc; +} + +/** + * @brief Main program. + * @param None + * @retval None + */ +void can_test(void) +{ + TxHeader.DLC = 2; + TxHeader.StdId = 0x321; + + /* Set the data to be transmitted */ + TxData[0] = ubKeyNumber + 1; + TxData[1] = 0xAD; + + /* Start the Transmission process */ + if (HAL_CAN_AddTxMessage(&CanHandle, &TxHeader, TxData, &TxMailbox) != HAL_OK) + { + /* Transmission request Error */ + Error_Handler(); + } +} + +void can_tx(uint16_t id, const uint8_t* data, uint8_t len) +{ + TxHeader.StdId = id; + TxHeader.DLC = len_to_dlc(len); + + while (HAL_CAN_GetTxMailboxesFreeLevel(&CanHandle) < 1) + { + } + + /* Start the Transmission process */ + if (HAL_CAN_AddTxMessage(&CanHandle, &TxHeader, (uint8_t*)data, &TxMailbox) != HAL_OK) + { + /* Transmission request Error */ + Error_Handler(); + } +} + +/** + * @brief This function is executed in case of error occurrence. + * @param None + * @retval None + */ +static void __NO_RETURN Error_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief Configures the CAN. + * @param None + * @retval None + */ +void can_config(void) +{ + CAN_FilterTypeDef sFilterConfig; + + /* Configure the CAN peripheral */ + CanHandle.Instance = CANx; + + CanHandle.MspInitCallback = CAN_MspInit; + CanHandle.MspDeInitCallback = CAN_MspDeInit; + + CanHandle.Init.TimeTriggeredMode = DISABLE; + CanHandle.Init.AutoBusOff = ENABLE; + CanHandle.Init.AutoWakeUp = DISABLE; + CanHandle.Init.AutoRetransmission = ENABLE; + CanHandle.Init.ReceiveFifoLocked = DISABLE; + CanHandle.Init.TransmitFifoPriority = DISABLE; + CanHandle.Init.Mode = CAN_MODE_NORMAL; + CanHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + CanHandle.Init.TimeSeg1 = CAN_BS1_6TQ; + CanHandle.Init.TimeSeg2 = CAN_BS2_5TQ; + CanHandle.Init.Prescaler = 4; + + if (HAL_CAN_Init(&CanHandle) != HAL_OK) + { + /* Initialization Error */ + Error_Handler(); + } + + /* Configure the CAN Filter */ + sFilterConfig.FilterBank = 0; + sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; + sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; + sFilterConfig.FilterIdHigh = 0x0000; + sFilterConfig.FilterIdLow = 0x0310; + sFilterConfig.FilterMaskIdHigh = 0x0000; + sFilterConfig.FilterMaskIdLow = 0x07F8; + sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; + sFilterConfig.FilterActivation = ENABLE; + sFilterConfig.SlaveStartFilterBank = 14; + + if (HAL_CAN_ConfigFilter(&CanHandle, &sFilterConfig) != HAL_OK) + { + /* Filter configuration Error */ + Error_Handler(); + } + + if (HAL_CAN_RegisterCallback(&CanHandle, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, CAN_RxFifo0MsgPendingCallback) != HAL_OK) + { + Error_Handler(); + } + + if (HAL_CAN_RegisterCallback(&CanHandle, HAL_CAN_TX_MAILBOX0_COMPLETE_CB_ID, CAN_TxMailboxCompleteCallback) != HAL_OK) + { + Error_Handler(); + } + + if (HAL_CAN_RegisterCallback(&CanHandle, HAL_CAN_TX_MAILBOX1_COMPLETE_CB_ID, CAN_TxMailboxCompleteCallback) != HAL_OK) + { + Error_Handler(); + } + + if (HAL_CAN_RegisterCallback(&CanHandle, HAL_CAN_TX_MAILBOX2_COMPLETE_CB_ID, CAN_TxMailboxCompleteCallback) != HAL_OK) + { + Error_Handler(); + } + + /* Start the CAN peripheral */ + if (HAL_CAN_Start(&CanHandle) != HAL_OK) + { + /* Start Error */ + Error_Handler(); + } + + /* Activate CAN RX notification */ + if (HAL_CAN_ActivateNotification(&CanHandle, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) + { + /* Notification Error */ + Error_Handler(); + } + + /* Activate CAN TX notification */ + if (HAL_CAN_ActivateNotification(&CanHandle, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK) + { + /* Notification Error */ + Error_Handler(); + } + + /* Configure Transmission process */ + TxHeader.StdId = 0x321; + TxHeader.ExtId = 0x01; + TxHeader.RTR = CAN_RTR_DATA; + TxHeader.IDE = CAN_ID_STD; + TxHeader.DLC = 2; + TxHeader.TransmitGlobalTime = DISABLE; +} + +/** + * @brief Rx Fifo 0 message pending callback in non blocking mode + * @param CanHandle: pointer to a CAN_HandleTypeDef structure that contains + * the configuration information for the specified CAN. + * @retval None + */ +static void CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) +{ + /* Get RX message */ + if (HAL_CAN_GetRxMessage(CanHandle, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) + { + /* Reception Error */ + Error_Handler(); + } + + if (RxHeader.IDE == CAN_ID_STD && + (RxHeader.StdId == CAN_ID_COMMAND_STW_TO_BACK || + RxHeader.StdId == CAN_ID_FEEDBACK_STW_TO_BACK)) + { + can_feedc0de_handle_frame(RxHeader.StdId, RxData, dlc_to_len(RxHeader.DLC)); + } + + // slightly yucky, but we don't want to block inside the IRQ handler + if (HAL_CAN_GetTxMailboxesFreeLevel(CanHandle) >= 2) + { + can_feedc0de_poll(); + } +} + +static void CAN_TxMailboxCompleteCallback(CAN_HandleTypeDef *hcan) +{ + // slightly yucky, but we don't want to block inside the IRQ handler + if (HAL_CAN_GetTxMailboxesFreeLevel(hcan) >= 2) + { + can_feedc0de_poll(); + } +} + +/** + * @brief CAN MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for DMA interrupt request enable + * @param hcan: CAN handle pointer + * @retval None + */ +static void CAN_MspInit(CAN_HandleTypeDef *hcan) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* CAN1 Periph clock enable */ + CANx_CLK_ENABLE(); + /* Enable GPIO clock ****************************************/ + CANx_GPIO_CLK_ENABLE(); + /* Enable AFIO clock and Remap CAN PINs to PB8 and PB9*******/ + CANx_AFIO_REMAP_CLK_ENABLE(); + CANx_AFIO_REMAP_RX_TX_PIN(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* CAN1 TX GPIO pin configuration */ + GPIO_InitStruct.Pin = CANx_TX_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Pull = GPIO_PULLUP; + + HAL_GPIO_Init(CANx_TX_GPIO_PORT, &GPIO_InitStruct); + + /* CAN1 RX GPIO pin configuration */ + GPIO_InitStruct.Pin = CANx_RX_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Pull = GPIO_PULLUP; + + HAL_GPIO_Init(CANx_RX_GPIO_PORT, &GPIO_InitStruct); + + /*##-3- Configure the NVIC #################################################*/ + /* NVIC configuration for CAN1 Reception complete interrupt */ + HAL_NVIC_SetPriority(CANx_RX_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(CANx_RX_IRQn); + + HAL_NVIC_SetPriority(CANx_TX_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(CANx_TX_IRQn); +} + +/** + * @brief CAN MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO to their default state + * @param hcan: CAN handle pointer + * @retval None + */ +static void CAN_MspDeInit(CAN_HandleTypeDef *hcan) +{ + /*##-1- Reset peripherals ##################################################*/ + CANx_FORCE_RESET(); + CANx_RELEASE_RESET(); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-initialize the CAN1 TX GPIO pin */ + HAL_GPIO_DeInit(CANx_TX_GPIO_PORT, CANx_TX_PIN); + /* De-initialize the CAN1 RX GPIO pin */ + HAL_GPIO_DeInit(CANx_RX_GPIO_PORT, CANx_RX_PIN); + + /*##-4- Disable the NVIC for CAN reception #################################*/ + HAL_NVIC_DisableIRQ(CANx_RX_IRQn); +} + +/** +* @brief This function handles CAN1 RX0 interrupt request. +* @param None +* @retval None +*/ +void CANx_RX_IRQHandler(void) +{ + HAL_CAN_IRQHandler(&CanHandle); +} + +void CANx_TX_IRQHandler(void) +{ + HAL_CAN_IRQHandler(&CanHandle); +} diff --git a/can.h b/can.h new file mode 100644 index 0000000..02ad8f4 --- /dev/null +++ b/can.h @@ -0,0 +1,29 @@ +#pragma once + +#define CAN_ID_COMMAND_STW_TO_BACK 0x311 +#define CAN_ID_COMMAND_BACK_TO_STW 0x312 +#define CAN_ID_COMMAND_STW_TO_FRONT 0x315 +#define CAN_ID_COMMAND_FRONT_TO_STW 0x316 + +#define CAN_ID_FEEDBACK_STW_TO_BACK 0x319 +#define CAN_ID_FEEDBACK_BACK_TO_STW 0x31A +#define CAN_ID_FEEDBACK_STW_TO_FRONT 0x31D +#define CAN_ID_FEEDBACK_FRONT_TO_STW 0x31E + +#define CAN_ID_HB_BACK_TO_STW 0x331 +#define CAN_ID_HB_FRONT_TO_STW 0x333 + + +#ifdef __cplusplus +extern "C" +{ +#endif + +void can_config(void); +void can_test(void); +void can_tx(uint16_t id, const uint8_t* data, uint8_t len); + + +#ifdef __cplusplus +} +#endif diff --git a/can_fc.h b/can_fc.h new file mode 100644 index 0000000..179c093 --- /dev/null +++ b/can_fc.h @@ -0,0 +1,216 @@ +#pragma once + +#ifdef __cplusplus +#include +#include +#include +#include + +#include "can.h" + +//#define FC_STRICT + +#define FC_PROTOCOL_ERROR() +#define Error_Handler() while(1) + +constexpr const uint8_t FC_CHUNK_SIZE = 7; +constexpr const uint8_t FC_TAG_INIT = 0x45; +constexpr const uint8_t FC_TAG_END = 0x7d; + +static uint8_t next_tag(uint8_t tag) +{ + if (tag == 0) + { + return FC_TAG_INIT; + } + else + { + return tag + 0x04; + } +} + +class FCSender +{ +public: + FCSender(uint16_t id) : id(id) + { + } + + bool tx_pending() + { + return pos_sent != len && pos_sent == pos_acked; + } + + bool transfer_in_progress() + { + return data != nullptr && pos_acked != len; + } + + bool transfer_finished() + { + return data != nullptr && pos_acked == len; + } + + void reset(const uint8_t* data, size_t len) + { + pos_sent = 0; + pos_acked = 0; + tag_sent = 0; + + this->data = data; + this->len = len; + } + + void handle_frame(const uint8_t* payload, uint8_t payload_len) + { + if (pos_sent == 0) + return; + + if (payload_len != 1) + return; + + if (payload[0] != tag_sent) + return; + + pos_acked = pos_sent; + } + + void tx() + { + uint8_t payload[1 + FC_CHUNK_SIZE]; + + // Still waiting for ack, or done transmitting + if (!tx_pending()) + return; + + size_t new_pos_sent = std::min(pos_sent + FC_CHUNK_SIZE, len); + uint8_t sent_size = new_pos_sent - pos_sent; + uint8_t new_tag_sent = next_tag(tag_sent); + if (new_tag_sent == FC_TAG_END) + Error_Handler(); + + payload[0] = new_tag_sent; + memcpy(&payload[1], data + pos_sent, sent_size); + can_tx(id, payload, 1 + sent_size); + + pos_sent = new_pos_sent; + tag_sent = new_tag_sent; + } + +private: + uint16_t id; + const uint8_t* data; + size_t len; + size_t pos_sent; + size_t pos_acked; + uint8_t tag_sent; +}; + +class FCReceiver +{ +public: + FCReceiver(uint16_t id, uint8_t* data, size_t len) : id(id) + { + reset(data, len); + } + + bool ack_pending() + { + return pos_received != pos_acked; + } + + bool transfer_in_progress() + { + return ready && data != nullptr && pos_acked != len; + } + + bool transfer_finished() + { + return ready && data != nullptr && pos_acked == len; + } + + void reset(uint8_t* data, size_t len) + { + // Poor man's mutex + ready = false; + + pos_received = 0; + pos_acked = 0; + tag_expected = next_tag(0); + + this->data = data; + this->len = len; + + ready = true; + } + + void handle_frame(const uint8_t* payload, uint8_t payload_len) + { + if (!transfer_in_progress()) + return; + + if (tag_expected == FC_TAG_END) + return; + + if (payload_len < 1) + return; + + // Reset receiver if frame with FC_TAG_INIT received when expecting different one + if (payload[0] == FC_TAG_INIT && tag_expected != FC_TAG_INIT) + reset(data, len); + + // Don't accept new data if we haven't acked the previous data yet + if (ack_pending()) + return; + + uint8_t data_len = payload_len - 1; + if (data_len > len - pos_received) + return; + + // Ignore all other tags + if (payload[0] != tag_expected) + return; + + memcpy(&data[pos_received], &payload[1], data_len); + + pos_received += data_len; + } + + void ack() + { + uint8_t payload[1]; + + if (!ack_pending()) + return; + + // Poor man's mutex + ready = false; + + // ISR may have called reset() in the mean time + if (!ack_pending()) + { + ready = true; + return; + } + + payload[0] = tag_expected; + can_tx(id, payload, sizeof(payload)); + + pos_acked = pos_received; + tag_expected = next_tag(tag_expected); + + ready = true; + } + +private: + bool ready; + + uint16_t id; + uint8_t* data; + size_t len; + size_t pos_received; + size_t pos_acked; + uint8_t tag_expected; +}; + +#endif // __cplusplus diff --git a/can_feedc0de.cpp b/can_feedc0de.cpp new file mode 100644 index 0000000..7f30651 --- /dev/null +++ b/can_feedc0de.cpp @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "protocol.h" +#include "can_fc.h" + +#include "can_feedc0de.h" + + +static_assert((sizeof(Command) + FC_CHUNK_SIZE - 1) / FC_CHUNK_SIZE < 15); + +void CANFeedc0de::poll() +{ + if (feedc0de_fcs.tx_pending()) + feedc0de_fcs.tx(); + + if (feedc0de_fcr.ack_pending()) + feedc0de_fcr.ack(); +} + +void CANFeedc0de::send_feedback(const Feedback& in) +{ + feedback = in; + feedc0de_fcs.reset(((uint8_t*)&feedback) + 2, sizeof(feedback) - 4); +} + +bool CANFeedc0de::get_command(Command& out) +{ + if (!feedc0de_fcr.transfer_finished()) + return false; + + out = command; + feedc0de_fcr.reset(((uint8_t*)&command) + 2, sizeof(command) - 4); + + return true; +} + +void CANFeedc0de::handle_frame(uint16_t id, uint8_t* frame, uint8_t len) +{ + switch (id) + { + case CAN_ID_FEEDBACK_STW_TO_BACK: + feedc0de_fcs.handle_frame(frame, len); + break; + case CAN_ID_COMMAND_STW_TO_BACK: + feedc0de_fcr.handle_frame(frame, len); + break; + default: + Error_Handler(); + } +} + +extern "C" +{ + +void can_feedc0de_handle_frame(uint16_t id, uint8_t* frame, uint8_t len) +{ + extern CANFeedc0de can_feedc0de; + can_feedc0de.handle_frame(id, frame, len); +} + +void can_feedc0de_poll() +{ + extern CANFeedc0de can_feedc0de; + can_feedc0de.poll(); +} + +} diff --git a/can_feedc0de.h b/can_feedc0de.h new file mode 100644 index 0000000..f80cf39 --- /dev/null +++ b/can_feedc0de.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +#include +#include "protocol.h" +#include "can_fc.h" +class CANFeedc0de +{ +public: + void poll(); + void handle_frame(uint16_t id, uint8_t* frame, uint8_t len); + void send_feedback(const Feedback& in); + bool get_command(Command& out); +private: + Command command; + Feedback feedback; + + FCSender feedc0de_fcs = FCSender(CAN_ID_FEEDBACK_BACK_TO_STW); + FCReceiver feedc0de_fcr = FCReceiver(CAN_ID_COMMAND_BACK_TO_STW, ((uint8_t *)&command) + 2, sizeof(command) - 4); +}; + +extern "C" +{ +#endif + +void can_feedc0de_handle_frame(uint16_t id, uint8_t* frame, uint8_t len); +void can_feedc0de_poll(); + +#ifdef __cplusplus +} +#endif diff --git a/main.cpp b/main.cpp index 6673bc8..11f7f63 100644 --- a/main.cpp +++ b/main.cpp @@ -34,6 +34,14 @@ extern "C" { extern const P rtP_Left; // default settings defined in BLDC_controller_data.c } +#ifdef FEATURE_CAN +#include "can.h" +#include "can_feedc0de.h" + +CANFeedc0de can_feedc0de; + +#endif + namespace { TIM_HandleTypeDef htim_right; TIM_HandleTypeDef htim_left; @@ -104,8 +112,6 @@ struct { Command command; Feedback feedback; - - void filtLowPass32(int16_t u, uint16_t coef, int32_t *y); void SystemClock_Config(); @@ -222,6 +228,11 @@ int main() int pwm = 0; int8_t dir = 1; #else + + can_config(); + MODIFY_REG(RCC->CR, RCC_CR_HSITRIM, (0x1aU << RCC_CR_HSITRIM_Pos)); + +#ifndef FEATURE_CAN HAL_UART_Receive_DMA(&huart2, (uint8_t *)&command, sizeof(command)); #endif @@ -265,6 +276,7 @@ int main() board_temp_deg_c = (TEMP_CAL_HIGH_DEG_C - TEMP_CAL_LOW_DEG_C) * (board_temp_adcFilt - TEMP_CAL_LOW_ADC) / (TEMP_CAL_HIGH_ADC - TEMP_CAL_LOW_ADC) + TEMP_CAL_LOW_DEG_C; sendFeedback(); + can_feedc0de.poll(); #ifdef FEATURE_BUTTON if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) @@ -1049,6 +1061,9 @@ void parseCommand() { bool any_parsed{false}; +#ifdef FEATURE_CAN + any_parsed = can_feedc0de.get_command(command); +#else for (int i = 0; i < 1; i++) { if (command.start != Command::VALID_HEADER) @@ -1058,6 +1073,13 @@ void parseCommand() if (command.checksum != checksum) continue; + any_parsed = true; + break; + } +#endif + + if (any_parsed) + { left.state = command.left; right.state = command.right; @@ -1070,12 +1092,8 @@ void parseCommand() command.start = Command::INVALID_HEADER; // Change the Start Frame for timeout detection in the next cycle timeoutCntSerial = 0; // Reset the timeout counter - - any_parsed = true; - break; } - - if (!any_parsed) + else { if (timeoutCntSerial++ >= 100) // Timeout qualification { @@ -1087,58 +1105,69 @@ void parseCommand() HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); +#ifndef FEATURE_CAN // Check periodically the received Start Frame. Try to re-sync by reseting the DMA if (main_loop_counter % 25 == 0) { HAL_UART_DMAStop(&huart2); HAL_UART_Receive_DMA(&huart2, (uint8_t *)&command, sizeof(command)); } +#endif } } } void sendFeedback() { - if (main_loop_counter % 50 == 0) { // Send data periodically - if(UART_DMA_CHANNEL->CNDTR == 0) { - feedback.start = Feedback::VALID_HEADER; + // Send data periodically + if (main_loop_counter % 50 != 0) + return; - feedback.left.angle = left.rtY.a_elecAngle; - feedback.right.angle = right.rtY.a_elecAngle; +#ifndef FEATURE_CAN + if (UART_DMA_CHANNEL->CNDTR != 0) + return; +#endif - feedback.left.speed = left.rtY.n_mot; - feedback.right.speed = right.rtY.n_mot; + feedback.start = Feedback::VALID_HEADER; - feedback.left.error = left.rtY.z_errCode; - feedback.right.error = right.rtY.z_errCode; + feedback.left.angle = left.rtY.a_elecAngle; + feedback.right.angle = right.rtY.a_elecAngle; - feedback.left.current = left.rtU.i_DCLink; - feedback.right.current = right.rtU.i_DCLink; + feedback.left.speed = left.rtY.n_mot; + feedback.right.speed = right.rtY.n_mot; - feedback.left.chops = left.chops; - feedback.right.chops = right.chops; - left.chops = 0; - right.chops = 0; + feedback.left.error = left.rtY.z_errCode; + feedback.right.error = right.rtY.z_errCode; - feedback.left.hallA = left.rtU.b_hallA; - feedback.left.hallB = left.rtU.b_hallB; - feedback.left.hallC = left.rtU.b_hallC; - feedback.right.hallA = right.rtU.b_hallA; - feedback.right.hallB = right.rtU.b_hallB; - feedback.right.hallC = right.rtU.b_hallC; + feedback.left.current = left.rtU.i_DCLink; + feedback.right.current = right.rtU.i_DCLink; - feedback.batVoltage = batVoltage * BAT_CALIB_REAL_VOLTAGE / BAT_CALIB_ADC; - feedback.boardTemp = board_temp_deg_c; - feedback.timeoutCntSerial = timeoutCntSerial; + feedback.left.chops = left.chops; + feedback.right.chops = right.chops; + left.chops = 0; + right.chops = 0; - feedback.checksum = calculateChecksum(feedback); + feedback.left.hallA = left.rtU.b_hallA; + feedback.left.hallB = left.rtU.b_hallB; + feedback.left.hallC = left.rtU.b_hallC; + feedback.right.hallA = right.rtU.b_hallA; + feedback.right.hallB = right.rtU.b_hallB; + feedback.right.hallC = right.rtU.b_hallC; - UART_DMA_CHANNEL->CCR &= ~DMA_CCR_EN; - UART_DMA_CHANNEL->CNDTR = sizeof(feedback); - UART_DMA_CHANNEL->CMAR = uint64_t(&feedback); - UART_DMA_CHANNEL->CCR |= DMA_CCR_EN; - } - } + feedback.batVoltage = batVoltage * BAT_CALIB_REAL_VOLTAGE / BAT_CALIB_ADC; + feedback.boardTemp = board_temp_deg_c; + feedback.timeoutCntSerial = timeoutCntSerial; + + feedback.checksum = calculateChecksum(feedback); + +#ifdef FEATURE_CAN + can_feedc0de.send_feedback(feedback); +#else + UART_DMA_CHANNEL->CCR &= ~DMA_CCR_EN; + UART_DMA_CHANNEL->CNDTR = sizeof(feedback); + UART_DMA_CHANNEL->CMAR = uint64_t(&feedback); + UART_DMA_CHANNEL->CCR |= DMA_CCR_EN; +#endif } } // anonymous namespace diff --git a/stm32f1xx_hal_conf.h b/stm32f1xx_hal_conf.h index 42311da..8a3b39b 100644 --- a/stm32f1xx_hal_conf.h +++ b/stm32f1xx_hal_conf.h @@ -36,7 +36,7 @@ extern "C" { */ #define HAL_MODULE_ENABLED #define HAL_ADC_MODULE_ENABLED -/* #define HAL_CAN_MODULE_ENABLED */ +#define HAL_CAN_MODULE_ENABLED /* #define HAL_CAN_LEGACY_MODULE_ENABLED */ /* #define HAL_CEC_MODULE_ENABLED */ #define HAL_CORTEX_MODULE_ENABLED @@ -129,7 +129,7 @@ extern "C" { #define PREFETCH_ENABLE 1U #define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */ -#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */ +#define USE_HAL_CAN_REGISTER_CALLBACKS 1U /* CAN register callback disabled */ #define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */ #define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */ #define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */