CAN Update
This commit is contained in:
331
firmware/Libs/CAN/can.c
Normal file
331
firmware/Libs/CAN/can.c
Normal file
@@ -0,0 +1,331 @@
|
||||
//
|
||||
// Created by enik on 02.06.22.
|
||||
//
|
||||
|
||||
#include "can.h"
|
||||
|
||||
//#include "Settings.h"
|
||||
|
||||
#if CAN_TESTING_LOOPBACK
|
||||
#define CAN_BASIC_MODE CAN_MODE_SILENT_LOOPBACK
|
||||
#else
|
||||
#define CAN_BASIC_MODE CAN_MODE_NORMAL
|
||||
#endif
|
||||
|
||||
#include "can_messenger.h"
|
||||
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern CAN_HandleTypeDef hcan2;
|
||||
|
||||
CAN_FilterTypeDef can1Filter;
|
||||
CAN_FilterTypeDef can2Filter;
|
||||
CAN_RxHeaderTypeDef can1RX, can2RX;
|
||||
u8_t can1Data[8] = {0,}, can2Data[8] = {0,};
|
||||
|
||||
typedef struct CAN_SPD_VAL {
|
||||
u32_t Prescaler;
|
||||
u32_t TimeSeg1;
|
||||
u32_t TimeSeg2;
|
||||
} CAN_SPD_VAL;
|
||||
|
||||
// PSC - 2 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd1000 = {.Prescaler = 2, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 3 | Time1 - 12 | Time2 - 2
|
||||
const CAN_SPD_VAL spd800 = {.Prescaler = 3, .TimeSeg1 = CAN_BS1_12TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 4 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd500 = {.Prescaler = 4, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 8 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd250 = {.Prescaler = 8, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 16 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd125 = {.Prescaler = 16, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 20 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd100 = {.Prescaler = 20, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 40 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd50 = {.Prescaler = 40, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 100 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd20 = {.Prescaler = 100, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 200 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd10 = {.Prescaler = 200, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set Speed for CAN Bus
|
||||
* @param[in] spd #CAN_SPEED enum
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetSpeed(CAN_SPEED spd, CAN_HandleTypeDef *can) {
|
||||
//if (HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING)
|
||||
HAL_CAN_Stop(can);
|
||||
can->Instance = (can == &hcan1) ? CAN1 : CAN2; // Can Instance
|
||||
can->Init.SyncJumpWidth = CAN_SJW_1TQ; // Default
|
||||
can->Init.TimeTriggeredMode = DISABLE; // Default
|
||||
can->Init.AutoBusOff = ENABLE; // Default
|
||||
can->Init.AutoWakeUp = ENABLE; // Default
|
||||
can->Init.AutoRetransmission = DISABLE; // Default
|
||||
can->Init.ReceiveFifoLocked = DISABLE; // Default
|
||||
can->Init.TransmitFifoPriority = ENABLE; // Default
|
||||
can->Init.Mode = CAN_BASIC_MODE; // Set Mode
|
||||
switch (spd) {
|
||||
case CAN_SPD_1000:
|
||||
can->Init.Prescaler = spd1000.Prescaler;
|
||||
can->Init.TimeSeg1 = spd1000.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd1000.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_800:
|
||||
can->Init.Prescaler = spd800.Prescaler;
|
||||
can->Init.TimeSeg1 = spd800.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd800.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_500:
|
||||
can->Init.Prescaler = spd500.Prescaler;
|
||||
can->Init.TimeSeg1 = spd500.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd500.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_250:
|
||||
can->Init.Prescaler = spd250.Prescaler;
|
||||
can->Init.TimeSeg1 = spd250.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd250.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_125:
|
||||
can->Init.Prescaler = spd125.Prescaler;
|
||||
can->Init.TimeSeg1 = spd125.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd125.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_100:
|
||||
can->Init.Prescaler = spd100.Prescaler;
|
||||
can->Init.TimeSeg1 = spd100.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd100.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_50:
|
||||
can->Init.Prescaler = spd50.Prescaler;
|
||||
can->Init.TimeSeg1 = spd50.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd50.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_20:
|
||||
can->Init.Prescaler = spd20.Prescaler;
|
||||
can->Init.TimeSeg1 = spd20.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd20.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_10:
|
||||
can->Init.Prescaler = spd10.Prescaler;
|
||||
can->Init.TimeSeg1 = spd10.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd10.TimeSeg2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (HAL_CAN_Init(can) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
filt->FilterBank = 0;
|
||||
filt->FilterFIFOAssignment = CAN_RX_FIFO0;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
filt->FilterBank = 14;
|
||||
filt->FilterFIFOAssignment = CAN_RX_FIFO1;
|
||||
filt->SlaveStartFilterBank = 14;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
filt->FilterMode = CAN_FILTERMODE_IDMASK;
|
||||
filt->FilterScale = CAN_FILTERSCALE_32BIT;
|
||||
filt->FilterIdHigh = 0x0000;
|
||||
filt->FilterIdLow = 0x0000;
|
||||
filt->FilterMaskIdHigh = 0x0000;
|
||||
filt->FilterMaskIdLow = 0x0000;
|
||||
filt->FilterActivation = ENABLE;
|
||||
if (HAL_CAN_ConfigFilter(can, filt) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
// HAL_CAN_Start(can);
|
||||
volatile HAL_StatusTypeDef status = HAL_CAN_Start(can);
|
||||
__NOP();
|
||||
volatile HAL_CAN_StateTypeDef st = HAL_CAN_GetState(can);
|
||||
if (st != HAL_CAN_STATE_LISTENING){
|
||||
__USR_BKPT();
|
||||
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
} else {
|
||||
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
}
|
||||
HAL_CAN_ActivateNotification(can,
|
||||
((can == &hcan1) ? CAN_IT_RX_FIFO0_MSG_PENDING : CAN_IT_RX_FIFO1_MSG_PENDING)
|
||||
| CAN_IT_ERROR | CAN_IT_BUSOFF | CAN_IT_LAST_ERROR_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Silent mode
|
||||
* @param[in] is_silent 1 if silent mode needed
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetMode(bool is_silent, CAN_HandleTypeDef *can) {
|
||||
can->Init.Mode = !is_silent ? CAN_MODE_NORMAL : CAN_MODE_SILENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Silent Loopback mode
|
||||
* @param[in] is_loopback 1 if loopback mode needed
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetLoopback(bool is_loopback, CAN_HandleTypeDef *can) {
|
||||
can->Init.Mode = !is_loopback ? CAN_MODE_NORMAL : CAN_MODE_SILENT_LOOPBACK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is opened
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Opened / 0 if Closed
|
||||
*/
|
||||
bool CAN_IsOpened(CAN_HandleTypeDef *can) {
|
||||
return HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is in silent mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Silent / 0 if not
|
||||
*/
|
||||
bool CAN_IsSilent(CAN_HandleTypeDef *can) {
|
||||
return (HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING &&
|
||||
(can->Init.Mode == CAN_MODE_SILENT ||
|
||||
can->Init.Mode == CAN_MODE_SILENT_LOOPBACK)) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is in silent loopbsck mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Silent Loopback / 0 if else
|
||||
*/
|
||||
bool CAN_IsLoopback(CAN_HandleTypeDef *can) {
|
||||
return (can->Init.Mode == CAN_MODE_SILENT_LOOPBACK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set filter mode
|
||||
* @param[in] id_only 1 if ID_LIST mode / 0 if ID_MASK mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterMode(bool id_only, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
filt->FilterMode = id_only ? CAN_FILTERMODE_IDLIST : CAN_FILTERMODE_IDMASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ID for filter
|
||||
* @warning Not realized
|
||||
* @param[in] filt_id Pointer to filter ID array
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterID(u8_t *filt_id, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Mask for filter
|
||||
* @warning Not realized
|
||||
* @param[in] filt_mask Pointer to filter mask
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterMask(u8_t *filt_mask, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common transmit prototype
|
||||
* @param[in] id CAN Packet ID
|
||||
* @param[in] ext 0 if 11-bit ID / 1 if 29-bit ID
|
||||
* @param[in] rtr 0 if standard frame / 1 if remote frame
|
||||
* @param[in] len Length of payload
|
||||
* @param[in] data Pointer to payload array
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_Transmit_Proto(u32_t id, bool ext, bool rtr, u8_t len, u8_t *data, CAN_HandleTypeDef *can) {
|
||||
CAN_TxHeaderTypeDef tx;
|
||||
tx.StdId = !ext ? id : 0;
|
||||
tx.ExtId = ext ? id : 0;
|
||||
tx.RTR = !rtr ? CAN_RTR_DATA : CAN_RTR_REMOTE;
|
||||
tx.IDE = !ext ? CAN_ID_STD : CAN_ID_EXT;
|
||||
tx.DLC = len;
|
||||
tx.TransmitGlobalTime = 0;
|
||||
u32_t mb;
|
||||
HAL_CAN_AddTxMessage(can, &tx, data, &mb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit standard (11-bit) data frame
|
||||
* @param[in] id 11-bit frame ID
|
||||
* @param[in] data Pointer to payload to be sent
|
||||
* @param[in] len Length of the payload to be sent
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_Transmit(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 0, 0, len, data, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit extended (29-bit) data frame
|
||||
* @param[in] id 29-bit frame ID
|
||||
* @param[in] data Pointer to payload to be sent
|
||||
* @param[in] len Length of the payload to be sent
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitExt(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto(id, 1, 0, len, data, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit standard (11-bit) remote frame
|
||||
* @param[in] id 11-bit frame ID
|
||||
* @param[in] len Length of remote frame
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 0, 1, len, NULL, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit extended (29-bit) remote frame
|
||||
* @param[in] id 29-bit frame ID
|
||||
* @param[in] len Length of remote frame
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitExtRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 1, 1, len, NULL, can);
|
||||
}
|
||||
|
||||
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
|
||||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &can1RX, can1Data) == HAL_OK) {
|
||||
//can_irq_receive(&can1RX, can1Data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) {
|
||||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &can2RX, can2Data) == HAL_OK) {
|
||||
can2_receive_from_irq(&can2RX, can2Data);
|
||||
//can_irq_receive(&can2RX, can2Data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
56
firmware/Libs/CAN/can.h
Normal file
56
firmware/Libs/CAN/can.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Created by enik on 02.06.22.
|
||||
//
|
||||
|
||||
#ifndef USBCANV1_CAN_H
|
||||
#define USBCANV1_CAN_H
|
||||
|
||||
//#include "libs.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
typedef uint8_t u8_t; ///< 8-bit unsigned
|
||||
typedef int8_t i8_t; ///< 8-bit signed
|
||||
typedef uint16_t u16_t; ///< 16-bit unsigned
|
||||
typedef int16_t i16_t; ///< 16-bit signed
|
||||
typedef uint32_t u32_t; ///< 32-bit unsigned
|
||||
typedef int32_t i32_t; ///< 32-bit signed
|
||||
typedef float fl_t; ///< float type
|
||||
|
||||
#define __USR_BKPT() __asm__ __volatile__("BKPT")
|
||||
|
||||
|
||||
/**
|
||||
* @brief CAN Speed in KBit/s
|
||||
*/
|
||||
typedef enum CAN_SPEED {
|
||||
CAN_SPD_1000,
|
||||
CAN_SPD_800,
|
||||
CAN_SPD_500,
|
||||
CAN_SPD_250,
|
||||
CAN_SPD_125,
|
||||
CAN_SPD_100,
|
||||
CAN_SPD_50,
|
||||
CAN_SPD_20,
|
||||
CAN_SPD_10,
|
||||
} CAN_SPEED;
|
||||
|
||||
void CAN_SetSpeed(CAN_SPEED spd, CAN_HandleTypeDef *can); //
|
||||
void CAN_SetMode(bool is_silent, CAN_HandleTypeDef *can); //
|
||||
void CAN_SetLoopback(bool is_loopback, CAN_HandleTypeDef *can); //
|
||||
bool CAN_IsOpened(CAN_HandleTypeDef *can); //
|
||||
bool CAN_IsSilent(CAN_HandleTypeDef *can); //
|
||||
bool CAN_IsLoopback(CAN_HandleTypeDef *can); //
|
||||
|
||||
void CAN_SetFilterMode(bool id_only, CAN_HandleTypeDef *can); //
|
||||
void CAN_SetFilterID(u8_t *filt_id, CAN_HandleTypeDef *can); //
|
||||
void CAN_SetFilterMask(u8_t *filt_mask, CAN_HandleTypeDef *can); //
|
||||
|
||||
void CAN_Transmit(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can); //
|
||||
void CAN_TransmitExt(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can); //
|
||||
void CAN_TransmitRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can); //
|
||||
void CAN_TransmitExtRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can); //
|
||||
|
||||
#endif //USBCANV1_CAN_H
|
||||
354
firmware/Libs/CAN/can_messenger.c
Normal file
354
firmware/Libs/CAN/can_messenger.c
Normal file
@@ -0,0 +1,354 @@
|
||||
//
|
||||
// Created by enik on 03.04.23.
|
||||
//
|
||||
|
||||
#include "can_messenger.h"
|
||||
#include "can.h"
|
||||
//#include "modCommands.h"
|
||||
#include "modPowerElectronics.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../RingBuffer/RingBuffer.h"
|
||||
|
||||
extern uint64_t TIM_Clock;
|
||||
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern CAN_HandleTypeDef hcan2;
|
||||
|
||||
uint64_t can1_transmit_clock = 0;
|
||||
uint64_t can2_transmit_clock = 0;
|
||||
|
||||
typedef struct CAN_MSG_t {
|
||||
u16_t id;
|
||||
u8_t len;
|
||||
u8_t msg[8];
|
||||
} CAN_MSG_t;
|
||||
|
||||
static volatile CAN_MSG_t can1_transmit_q_msg[45]; // 540 bytes
|
||||
static volatile CAN_MSG_t can2_transmit_q_msg[10]; // 120 bytes
|
||||
static volatile RINGBUF_t can1_ring;
|
||||
static volatile RINGBUF_t can2_ring;
|
||||
|
||||
static volatile CAN_MSG_t can1_buf = {0,}; // Buf for 1 packet
|
||||
static volatile CAN_MSG_t can2_buf = {0,}; // Buf for 1 packet
|
||||
|
||||
static volatile CAN_MSG_t can1_tx_buf = {0,}; // Buf for 1 TX packet
|
||||
static volatile CAN_MSG_t can2_tx_buf = {0,}; // Buf for 1 TX packet
|
||||
|
||||
extern modPowerElectronicsPackStateTypedef packState;
|
||||
extern modConfigGeneralConfigStructTypedef *generalConfig;
|
||||
|
||||
static volatile bool threshold_request = 0;
|
||||
static volatile bool active_request = 0;
|
||||
|
||||
void can_msgr_init() {
|
||||
RingBuf_Init((void *) &can1_transmit_q_msg, 45, sizeof(CAN_MSG_t), (RINGBUF_t *) &can1_ring);
|
||||
RingBuf_Init((void *) &can2_transmit_q_msg, 10, sizeof(CAN_MSG_t), (RINGBUF_t *) &can2_ring);
|
||||
}
|
||||
|
||||
void transmitCan1Packet() {
|
||||
if ((TIM_Clock - can1_transmit_clock) < 1000) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t data1[8] = {0x45};
|
||||
CAN_Transmit(300, data1, 8, &hcan1);
|
||||
can1_transmit_clock = TIM_Clock;
|
||||
return;
|
||||
|
||||
CAN_TxHeaderTypeDef header;
|
||||
header.IDE = CAN_ID_STD;
|
||||
header.RTR = CAN_RTR_DATA;
|
||||
header.StdId = 0x444;
|
||||
header.DLC = 1;
|
||||
|
||||
uint8_t data[32] = {};
|
||||
uint32_t mailbox = 0;
|
||||
|
||||
// sending SOC, SOH and number of cells
|
||||
uint16_t id = 0x101;
|
||||
memcpy(data, &id, sizeof(id));
|
||||
memcpy(data + 2, &packState.SoC, sizeof(packState.SoC));
|
||||
memcpy(data + 6, &packState.SoCCapacityAh, sizeof(packState.SoCCapacityAh));
|
||||
memcpy(data + 10, &generalConfig->noOfCellsSeries, sizeof(generalConfig->noOfCellsSeries));
|
||||
header.DLC = 11;
|
||||
HAL_CAN_AddTxMessage(&hcan1, &header, data, &mailbox);
|
||||
|
||||
// sending charge current, discharge current // TODO
|
||||
id = 0x102;
|
||||
memcpy(data, &id, sizeof(id));
|
||||
memcpy(data + 2, &packState.packCurrent, sizeof(packState.packCurrent));
|
||||
memcpy(data + 6, &packState.loCurrentLoadCurrent, sizeof(packState.loCurrentLoadCurrent));
|
||||
header.DLC = 10;
|
||||
HAL_CAN_AddTxMessage(&hcan1, &header, data, &mailbox);
|
||||
|
||||
// sending BMS state, input state, output state // TODO
|
||||
id = 0x103;
|
||||
memcpy(data, &id, sizeof(id));
|
||||
memcpy(data + 2, &packState.cellVoltageLow, sizeof(packState.cellVoltageLow));
|
||||
memcpy(data + 6, &packState.cellVoltageAverage, sizeof(packState.cellVoltageAverage));
|
||||
memcpy(data + 10, &packState.cellVoltageHigh, sizeof(packState.cellVoltageHigh));
|
||||
header.DLC = 12;
|
||||
HAL_CAN_AddTxMessage(&hcan1, &header, data, &mailbox);
|
||||
|
||||
// sending cell voltages
|
||||
id = 0x200;
|
||||
for (int cellPointer = 0;
|
||||
cellPointer < generalConfig->noOfCellsSeries * generalConfig->noOfParallelModules; ++cellPointer) {
|
||||
++id;
|
||||
memcpy(data, &id, sizeof(id));
|
||||
float voltage = 0;
|
||||
if (packState.cellVoltagesIndividual[cellPointer].cellBleedActive)
|
||||
voltage = packState.cellVoltagesIndividual[cellPointer].cellVoltage * -1000;
|
||||
else
|
||||
voltage = packState.cellVoltagesIndividual[cellPointer].cellVoltage * 1000;
|
||||
memcpy(data + 2, &voltage, sizeof(voltage));
|
||||
header.DLC = 6;
|
||||
HAL_CAN_AddTxMessage(&hcan1, &header, data, &mailbox);
|
||||
}
|
||||
|
||||
// sending temperatures
|
||||
id = 0x300;
|
||||
for (int sensorPointer = 0; sensorPointer < NoOfTempSensors; ++sensorPointer) {
|
||||
++id;
|
||||
memcpy(data, &id, sizeof(id));
|
||||
float temperature = packState.temperatures[sensorPointer];
|
||||
memcpy(data + 2, &temperature, sizeof(temperature));
|
||||
header.DLC = 6;
|
||||
HAL_CAN_AddTxMessage(&hcan1, &header, data, &mailbox);
|
||||
}
|
||||
|
||||
can1_transmit_clock = TIM_Clock;
|
||||
}
|
||||
|
||||
int getIndexBySoc() {
|
||||
const float soc = packState.SoC;
|
||||
if (soc <= 0) {
|
||||
return 0;
|
||||
} else if (soc <= 10 && soc > 0) {
|
||||
return 1;
|
||||
} else if (soc <= 20 && soc > 10) {
|
||||
return 2;
|
||||
} else if (soc <= 30 && soc > 20) {
|
||||
return 3;
|
||||
} else if (soc <= 40 && soc > 30) {
|
||||
return 4;
|
||||
} else if (soc <= 50 && soc > 40) {
|
||||
return 5;
|
||||
} else if (soc <= 60 && soc > 50) {
|
||||
return 6;
|
||||
} else if (soc <= 70 && soc > 60) {
|
||||
return 7;
|
||||
} else if (soc <= 80 && soc > 70) {
|
||||
return 8;
|
||||
} else if (soc <= 95 && soc > 80) {
|
||||
return 9;
|
||||
} else if (soc > 95) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int getIndexByTemperature() {
|
||||
const float temp = packState.tempBatteryAverage;
|
||||
if (temp < 0) {
|
||||
return 0;
|
||||
} else if (temp < 2 && temp >= 0) {
|
||||
return 1;
|
||||
} else if (temp < 7 && temp >= 2) {
|
||||
return 2;
|
||||
} else if (temp < 15 && temp >= 7) {
|
||||
return 3;
|
||||
} else if (temp < 20 && temp >= 15) {
|
||||
return 4;
|
||||
} else if (temp < 45 && temp >= 20) {
|
||||
return 5;
|
||||
} else if (temp < 50 && temp >= 45) {
|
||||
return 6;
|
||||
} else if (temp < 55 && temp >= 50) {
|
||||
return 7;
|
||||
} else if (temp >= 55) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16_t get_table_current() {
|
||||
// sending table current and end-of-charge current command
|
||||
const int socIndex = getIndexBySoc();
|
||||
const int temperatureIndex = getIndexByTemperature();
|
||||
float tableCurrent = 0;
|
||||
if (socIndex != -1 && temperatureIndex != -1) {
|
||||
float tableValue = generalConfig->externalChargeCurrentTable[temperatureIndex][socIndex];
|
||||
float pureCurrent = generalConfig->externalChargeUnitTable[temperatureIndex][socIndex];
|
||||
return (u16_t) roundf(pureCurrent ? tableValue : generalConfig->batteryCapacity * tableValue);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can2_send_status() {
|
||||
// id - CAN_BMS_STATUS
|
||||
// len - 7
|
||||
// msg[0:0] = 0: permission, 1: end_charge, 2: charging
|
||||
// msg[1:2] = set_curr
|
||||
// msg[3:6] = end_voltage
|
||||
|
||||
u8_t b0 = 0;
|
||||
b0 |= (packState.chargeAllowed & 0b1) << 0; // bit 0
|
||||
b0 |= ((packState.SoC > 95) & 0b1) << 1; // bit 1
|
||||
b0 |= (charge_switch_state & 0b1) << 2; // bit 2
|
||||
|
||||
u16_t curr = get_table_current();
|
||||
const float endVoltage = generalConfig->cellHardOverVoltage * (float) generalConfig->noOfCellsSeries;
|
||||
|
||||
can2_buf.id = CAN_BMS_STATUS;
|
||||
can2_buf.len = 7;
|
||||
can2_buf.msg[0] = b0; // set msg[0]
|
||||
memcpy((void *) can2_buf.msg + sizeof(b0), &curr, sizeof(curr)); // set msg[1]
|
||||
memcpy((void *) can2_buf.msg + sizeof(b0) + sizeof(curr), &endVoltage, sizeof(endVoltage)); // set msg[3]
|
||||
RingBuf_CellPut(&can2_buf, &can2_ring);
|
||||
}
|
||||
|
||||
void can2_send_volt_threshold() {
|
||||
// id - CAN_BMS_VOLT_THRESH
|
||||
// len - 8
|
||||
// msg[0:3] = start_voltage
|
||||
// msg[4:7] = end_voltage
|
||||
|
||||
// TODO: Check it
|
||||
const float startVoltage = generalConfig->cellHardUnderVoltage * (float) generalConfig->noOfCellsSeries;
|
||||
const float endVoltage = generalConfig->cellHardOverVoltage * (float) generalConfig->noOfCellsSeries;
|
||||
|
||||
can2_buf.id = CAN_BMS_VOLT_THRESH;
|
||||
can2_buf.len = 8;
|
||||
memcpy((void *) can2_buf.msg, &startVoltage, sizeof(startVoltage));
|
||||
memcpy((void *) can2_buf.msg + sizeof(startVoltage), &endVoltage, sizeof(endVoltage));
|
||||
RingBuf_CellPut(&can2_buf, &can2_ring);
|
||||
}
|
||||
|
||||
void can2_send_volt_alarm() {
|
||||
// id - CAN_BMS_VOLT_ALARM
|
||||
// len - 8
|
||||
// msg[0:3] = volt_alarm_lo
|
||||
// msg[4:7] = volt_alarm_up
|
||||
|
||||
// TODO: Check it
|
||||
const float startFaultVoltage = generalConfig->cellLCSoftUnderVoltage * (float) generalConfig->noOfCellsSeries;
|
||||
const float endFaultVoltage = generalConfig->cellSoftOverVoltage * (float) generalConfig->noOfCellsSeries;
|
||||
|
||||
can2_buf.id = CAN_BMS_VOLT_ALARM;
|
||||
can2_buf.len = 8;
|
||||
memcpy((void *) can2_buf.msg, &startFaultVoltage, sizeof(startFaultVoltage));
|
||||
memcpy((void *) can2_buf.msg + sizeof(startFaultVoltage), &endFaultVoltage, sizeof(endFaultVoltage));
|
||||
RingBuf_CellPut(&can2_buf, &can2_ring);
|
||||
}
|
||||
|
||||
void can2_send_current() {
|
||||
// id - CAN_BMS_CURRENT
|
||||
// len - 8
|
||||
// msg[0:1] = [u16] start_current
|
||||
// msg[2:3] = [u16] start_current_interval
|
||||
// msg[4:5] = [u16] set_current
|
||||
// msg[6:7] = [u16] end_current
|
||||
|
||||
u16_t chargeStartingCurrent = 15; // TODO move to generalConfig
|
||||
u16_t chargeStartingCurrentInterval = 20; // in seconds TODO move to generalConfig
|
||||
u16_t curr = get_table_current();
|
||||
u16_t chargeEndingCurrent = 5; // TODO move to generalConfig
|
||||
|
||||
can2_buf.id = CAN_BMS_CURRENT;
|
||||
can2_buf.len = 8;
|
||||
memcpy((void *) can2_buf.msg, &chargeStartingCurrent, sizeof(chargeStartingCurrent));
|
||||
memcpy((void *) can2_buf.msg + sizeof(chargeStartingCurrent),
|
||||
&chargeStartingCurrentInterval,
|
||||
sizeof(chargeStartingCurrentInterval));
|
||||
memcpy((void *) can2_buf.msg + sizeof(chargeStartingCurrent) + sizeof(chargeStartingCurrentInterval),
|
||||
&curr,
|
||||
sizeof(curr));
|
||||
memcpy((void *) can2_buf.msg + sizeof(chargeStartingCurrent) + sizeof(chargeStartingCurrentInterval) + sizeof(curr),
|
||||
&chargeEndingCurrent,
|
||||
sizeof(chargeEndingCurrent));
|
||||
|
||||
RingBuf_CellPut(&can2_buf, &can2_ring);
|
||||
}
|
||||
|
||||
void can2_send_active() {
|
||||
// id - CAN_BMS_ACT_VAL
|
||||
// len - 6
|
||||
// msg[0:3] = [float] sum_voltage
|
||||
// msg[4:5] = [u16] sum_current
|
||||
|
||||
can2_buf.id = CAN_BMS_ACT_VAL;
|
||||
can2_buf.len = 6;
|
||||
memcpy((void *) can2_buf.msg, &packState.packVoltage, sizeof(packState.packVoltage));
|
||||
memcpy((void *) can2_buf.msg + sizeof(packState.packVoltage),
|
||||
&packState.packCurrent, sizeof(packState.packCurrent));
|
||||
RingBuf_CellPut(&can2_buf, &can2_ring);
|
||||
}
|
||||
|
||||
|
||||
void transmitCan2Packet() {
|
||||
if (threshold_request) {
|
||||
// Send 501 - status, 503 - volt. threshold, 504 - volt. alarm, 505 - current
|
||||
can2_send_status(); // 501
|
||||
can2_send_volt_threshold(); // 503
|
||||
can2_send_volt_alarm(); // 504
|
||||
can2_send_current(); // 505
|
||||
|
||||
threshold_request = 0;
|
||||
}
|
||||
if (active_request){
|
||||
// send 507 - active values
|
||||
can2_send_active();
|
||||
active_request = 0;
|
||||
}
|
||||
|
||||
if ((TIM_Clock - can2_transmit_clock) < 10) {
|
||||
return;
|
||||
}
|
||||
can2_transmit_clock = TIM_Clock;
|
||||
|
||||
can2_send_status();
|
||||
}
|
||||
|
||||
void transmitCanPacketFromQueueCan1(void) {
|
||||
if (!HAL_CAN_GetTxMailboxesFreeLevel(&hcan1)) return; // if no free mailboxes
|
||||
u16_t len = 0;
|
||||
RingBuf_Available(&len, &can1_ring);
|
||||
if (!len) return;
|
||||
|
||||
RingBuf_CellRead(&can1_tx_buf, &can1_ring);
|
||||
CAN_Transmit(can1_tx_buf.id, can1_tx_buf.msg, can1_tx_buf.len, &hcan1);
|
||||
}
|
||||
|
||||
u32_t ctr;
|
||||
|
||||
void transmitCanPacketFromQueueCan2(void) {
|
||||
if (!HAL_CAN_GetTxMailboxesFreeLevel(&hcan2)) return; // if no free mailboxes
|
||||
u16_t len = 0;
|
||||
RingBuf_Available(&len, &can2_ring);
|
||||
if (!len) return;
|
||||
|
||||
// volatile u32_t delta = HAL_GetTick() - ctr;
|
||||
// ctr = HAL_GetTick();
|
||||
//
|
||||
// __NOP();
|
||||
|
||||
RingBuf_CellRead(&can2_tx_buf, &can2_ring);
|
||||
CAN_Transmit(can2_tx_buf.id, can2_tx_buf.msg, can2_tx_buf.len, &hcan2);
|
||||
}
|
||||
|
||||
|
||||
void can2_receive_from_irq(CAN_RxHeaderTypeDef *hdr, uint8_t *data) {
|
||||
// If remote frame with STD ID
|
||||
if (hdr->RTR == CAN_RTR_REMOTE && hdr->IDE == CAN_ID_STD) {
|
||||
if (hdr->StdId == CAN_BMS_THRESH_REQ) { // if Threshold request
|
||||
threshold_request = 1;
|
||||
} else if (hdr->StdId == CAN_BMS_ACT_REQ) { // if Active request
|
||||
active_request = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
firmware/Libs/CAN/can_messenger.h
Normal file
38
firmware/Libs/CAN/can_messenger.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by enik on 03.04.23.
|
||||
//
|
||||
|
||||
#ifndef BMS_V3_CAN_MESSENGER_H
|
||||
#define BMS_V3_CAN_MESSENGER_H
|
||||
|
||||
#include "../Core/Inc/main.h"
|
||||
|
||||
/**
|
||||
* @brief CAN BMS ID description enum
|
||||
*/
|
||||
typedef enum CAN_BMS_ID {
|
||||
CAN_BMS_HEARTBEAT = 0x500U, ///< [BMS->Charger][RTR] Heartbeat
|
||||
CAN_BMS_STATUS = 0x501U, ///< [BMS->Charger][L:7] Status packet
|
||||
CAN_BMS_THRESH_REQ = 0x502U, ///< [Charger->BMS][RTR] Threshold request
|
||||
CAN_BMS_VOLT_THRESH = 0x503U, ///< [BMS->Charger][L:8] Voltage threshold
|
||||
CAN_BMS_VOLT_ALARM = 0x504U, ///< [BMS->Charger][L:8] Voltage alarm
|
||||
CAN_BMS_CURRENT = 0x505U, ///< [BMS->Charger][L:6] Current control
|
||||
CAN_BMS_ACT_REQ = 0x506U, ///< [Charger->BMS][RTR] Active values request
|
||||
CAN_BMS_ACT_VAL = 0x507U, ///< [BMS->Charger][L:6] Active values
|
||||
} CAN_BMS_ID;
|
||||
|
||||
void can_msgr_init();
|
||||
|
||||
void transmitCan1Packet();
|
||||
int getIndexBySoc();
|
||||
int getIndexByTemperature();
|
||||
void transmitCan2Packet();
|
||||
void addCanPacketToQueue(uint16_t id, uint8_t len, uint8_t *data, uint8_t *queue, uint16_t *queueSize);
|
||||
//void transmitCanPacketFromQueue(uint8_t* queue, uint16_t* queueSize, CAN_HandleTypeDef* hcan);
|
||||
|
||||
void transmitCanPacketFromQueueCan1(void);
|
||||
void transmitCanPacketFromQueueCan2(void);
|
||||
|
||||
void can2_receive_from_irq(CAN_RxHeaderTypeDef *hdr, uint8_t* data);
|
||||
|
||||
#endif //BMS_V3_CAN_MESSENGER_H
|
||||
236
firmware/Libs/RingBuffer/RingBuffer.c
Normal file
236
firmware/Libs/RingBuffer/RingBuffer.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
*******************************************
|
||||
* @file RingBuffer.c
|
||||
* @author Dmitriy Semenov / Crazy_Geeks
|
||||
* @version 1.2
|
||||
* @date 05-March-2022
|
||||
* @brief Source file for RingBuffer lib
|
||||
* @note https://crazygeeks.ru/c-ringbuffer/
|
||||
*******************************************
|
||||
*/
|
||||
|
||||
#include "RingBuffer.h"
|
||||
|
||||
/**
|
||||
* @addtogroup RING_BUF
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Init ring buffer
|
||||
*
|
||||
* @param[in] buf Pointer to the allocated buffer
|
||||
* @param[in] size Size of buffer
|
||||
* @param[in] cellsize Size of 1 cell [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_Init(void *buf, u16_t size, size_t cellsize, RINGBUF_t *rb) {
|
||||
rb->size = size; // size of array
|
||||
rb->cell_size = cellsize; // size of 1 cell of array
|
||||
rb->buf = buf; // set pointer to buffer
|
||||
RingBuf_Clear(rb); // clear all
|
||||
return rb->buf ? RINGBUF_OK : RINGBUF_PARAM_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear ring buffer
|
||||
* @note Disable interrupts while clearing
|
||||
*
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_Clear(RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
rb->head = rb->tail = 0;
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check available size to read
|
||||
*
|
||||
* @param[out] len Size to read [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_Available(u16_t *len, RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
if (rb->head < rb->tail)
|
||||
*len = rb->size - rb->tail + rb->head;
|
||||
else
|
||||
*len = rb->head - rb->tail;
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put byte to the buffer
|
||||
*
|
||||
* @param[in] data Data byte to be put [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_BytePut(const u8_t data, RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
rb->buf[rb->head++] = data; // put byte in cell and increment data
|
||||
if (rb->head >= rb->size) // if overflow
|
||||
rb->head = 0; // set to start
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put 1 cell to the buffer
|
||||
* @param[in] data Pointer to data
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_CellPut(const void *data, RINGBUF_t *rb) {
|
||||
return RingBuf_DataPut(data, 1, rb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put some data to the buffer
|
||||
*
|
||||
* @param[in] data Data to be put
|
||||
* @param[in] len Length of data to be written [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_DataPut(const void *data, u16_t len, RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
if (len > rb->size)
|
||||
return RINGBUF_OVERFLOW;
|
||||
const char *input = data; // recast pointer
|
||||
// INPUT data index start address
|
||||
size_t s_addr = 0;
|
||||
// available space in the end of buffer
|
||||
size_t space = rb->size - rb->head;
|
||||
if (len > space) { // if len > available space
|
||||
// copy data to available space
|
||||
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], space * rb->cell_size);
|
||||
// next writing will start from 0
|
||||
rb->head = 0;
|
||||
// new start address = space length
|
||||
s_addr = space;
|
||||
// new length = len-space
|
||||
len -= space;
|
||||
}
|
||||
// copy all the data to the buf storage
|
||||
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], len * rb->cell_size);
|
||||
// shift to the next head
|
||||
rb->head += len;
|
||||
if (rb->head >= rb->size)
|
||||
rb->head = 0;
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read next byte from the buffer
|
||||
*
|
||||
* @param[out] data Data byte from the buffer
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_ByteRead(u8_t *data, RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
RINGBUF_STATUS st = RingBuf_ByteWatch(data, rb);
|
||||
if (st != RINGBUF_OK)
|
||||
return st;
|
||||
rb->tail++;
|
||||
if (rb->tail >= rb->size)
|
||||
rb->tail = 0;
|
||||
return st;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read 1 cell from buf
|
||||
* @param[out] data Data cell from the buffer
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_CellRead(void *data, RINGBUF_t *rb) {
|
||||
return RingBuf_DataRead(data, 1, rb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read some next data from the buffer
|
||||
*
|
||||
* @param[out] data Data from the buffer
|
||||
* @param[in] len Length of data to be read [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_DataRead(void *data, u16_t len, RINGBUF_t *rb) {
|
||||
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
|
||||
// read data
|
||||
RINGBUF_STATUS st = RingBuf_DataWatch(data, len, rb);
|
||||
if (st != RINGBUF_OK)
|
||||
return st;
|
||||
// shift to the next head
|
||||
rb->tail += len;
|
||||
if (rb->tail >= rb->size)
|
||||
rb->tail = 0;
|
||||
return st;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Watch current byte in buf
|
||||
* @note Reads data without shifting in the buffer
|
||||
*
|
||||
* @param[out] data Pointer to data byte got from buffer
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_ByteWatch(u8_t *data, RINGBUF_t *rb) {
|
||||
if (data == NULL) return RINGBUF_PARAM_ERR;
|
||||
*data = rb->buf[rb->tail];
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Watch 1 cell from buf
|
||||
* @note Reads data without shifting in the buffer
|
||||
*
|
||||
* @param[out] data Pointer to data cell got from buffer
|
||||
* @param[in] #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_CellWatch(void *data, RINGBUF_t *rb) {
|
||||
return RingBuf_DataWatch(data, 1, rb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Watch current data in the buf
|
||||
* @note Reads data without shifting in the buffer
|
||||
*
|
||||
* @param[out] data Data from buffer
|
||||
* @param[in] len Length of data to be read [bytes]
|
||||
* @param[in] rb #RINGBUF_t structure instance
|
||||
* @return #RINGBUF_STATUS enum
|
||||
*/
|
||||
RINGBUF_STATUS RingBuf_DataWatch(void *data, u16_t len, RINGBUF_t *rb) {
|
||||
if (data == NULL)
|
||||
return RINGBUF_PARAM_ERR;
|
||||
if (len > rb->size)
|
||||
return RINGBUF_OVERFLOW;
|
||||
// OUTPUT data index start address
|
||||
u16_t s_addr = 0;
|
||||
// available space in the end of buffer
|
||||
u16_t space = rb->size - rb->tail;
|
||||
u16_t loc_tail = rb->tail;
|
||||
if (len > space) { // if len > available space
|
||||
// recast pointer to u8_t
|
||||
// copy data from available space
|
||||
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], space * rb->cell_size);
|
||||
// next reading will start from 0
|
||||
loc_tail = 0;
|
||||
// new start address - space length
|
||||
s_addr = space;
|
||||
// new length - len-space
|
||||
len -= space;
|
||||
}
|
||||
// copy all the data from the buf storage
|
||||
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], len * rb->cell_size);
|
||||
return RINGBUF_OK;
|
||||
}
|
||||
|
||||
/// @} RING_BUF Group
|
||||
77
firmware/Libs/RingBuffer/RingBuffer.h
Normal file
77
firmware/Libs/RingBuffer/RingBuffer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
*******************************************
|
||||
* @file RingBuffer.h
|
||||
* @author Dmitriy Semenov / Crazy_Geeks
|
||||
* @version 1.2
|
||||
* @date 05-March-2022
|
||||
* @brief Header file for RingBuffer lib
|
||||
* @note https://crazygeeks.ru/c-ringbuffer/
|
||||
*******************************************
|
||||
*/
|
||||
#ifndef RING_BUF_H_
|
||||
#define RING_BUF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libs.h"
|
||||
|
||||
/**
|
||||
* @addtogroup RING_BUF
|
||||
* @brief Ring buffer implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @struct RINGBUF_t
|
||||
* @brief Ring buffer unit
|
||||
*/
|
||||
typedef struct RINGBUF_t{
|
||||
u8_t *buf; ///< Storage of the buffer
|
||||
volatile size_t tail; ///< Place of read point [cells]
|
||||
volatile size_t head; ///< Place of write point [cells]
|
||||
volatile size_t size; ///< Size of buffer [cells]
|
||||
volatile size_t cell_size; ///< Size of one cell [bytes]
|
||||
} RINGBUF_t;
|
||||
|
||||
/**
|
||||
* @enum RINGBUF_STATUS
|
||||
* @brief Ring buf status enum
|
||||
*
|
||||
* RINGBUF_X
|
||||
* X: OK, ERR, PARAM_ERR, OVERFLOW
|
||||
*/
|
||||
typedef enum RINGBUF_STATUS{
|
||||
RINGBUF_OK, ///< Success status
|
||||
RINGBUF_ERR, ///< Error
|
||||
RINGBUF_PARAM_ERR, ///< Parameter error
|
||||
RINGBUF_OVERFLOW, ///< Buffer overflow
|
||||
} RINGBUF_STATUS;
|
||||
|
||||
RINGBUF_STATUS RingBuf_Init(void *buf, u16_t size, size_t cellsize, RINGBUF_t *rb); // Init buf
|
||||
RINGBUF_STATUS RingBuf_Clear(RINGBUF_t *rb); // Clear buf
|
||||
RINGBUF_STATUS RingBuf_Available(u16_t *len, RINGBUF_t *rb); // Data available
|
||||
|
||||
// Put: add data to buffer
|
||||
RINGBUF_STATUS RingBuf_BytePut(u8_t data, RINGBUF_t *rb); // Put byte to the buf
|
||||
RINGBUF_STATUS RingBuf_CellPut(const void *data, RINGBUF_t *rb); // Put 1 cell to the buf
|
||||
RINGBUF_STATUS RingBuf_DataPut(const void *data, u16_t len, RINGBUF_t *rb); // Put data to the buf
|
||||
|
||||
// Read: Get data & flush it
|
||||
RINGBUF_STATUS RingBuf_ByteRead(u8_t *data, RINGBUF_t *rb); // Read byte from buf
|
||||
RINGBUF_STATUS RingBuf_CellRead(void *data, RINGBUF_t *rb); // Read 1 cell from buf
|
||||
RINGBUF_STATUS RingBuf_DataRead(void *data, u16_t len, RINGBUF_t *rb); // Read data from buf
|
||||
|
||||
// Watch: Get data without flushing
|
||||
RINGBUF_STATUS RingBuf_ByteWatch(u8_t *data, RINGBUF_t *rb); // Watch byte from buf
|
||||
RINGBUF_STATUS RingBuf_CellWatch(void *data, RINGBUF_t *rb); // Watch 1 cell from buf
|
||||
RINGBUF_STATUS RingBuf_DataWatch(void *data, u16_t len, RINGBUF_t *rb); // Watch data form buf
|
||||
|
||||
/// @} RING_BUF Group
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RING_BUF_H_ */
|
||||
49
firmware/Libs/Utils/micros.c
Executable file
49
firmware/Libs/Utils/micros.c
Executable file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Created by enik on 18.02.2022.
|
||||
//
|
||||
|
||||
#include "micros.h"
|
||||
|
||||
#define DWT_CYCCNT *(volatile uint32_t*)0xE0001004
|
||||
#define DWT_CONTROL *(volatile uint32_t*)0xE0001000
|
||||
#define SCB_DEMCR *(volatile uint32_t*)0xE000EDFC
|
||||
|
||||
static volatile bool dwt_enabled = 0;
|
||||
|
||||
/**
|
||||
* @brief Enable DWT Counter
|
||||
*/
|
||||
void EnableDWT(void){
|
||||
SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // allow to use DWT
|
||||
DWT_CONTROL |= DWT_CTRL_CYCCNTENA_Msk; // Start DWT counter
|
||||
dwt_enabled = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delay Microseconds
|
||||
* @param[in] val Value in microseconds to delay
|
||||
*/
|
||||
void DelayMicros(u32_t val){
|
||||
if (!dwt_enabled) EnableDWT();
|
||||
u32_t us_count_tic = val * (SystemCoreClock / 1000000); // get delay value in ticks
|
||||
DWT->CYCCNT = 0U; // zero counter value
|
||||
while(DWT->CYCCNT < us_count_tic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start code measure from this point
|
||||
*/
|
||||
void StartCodeMeasure(void){
|
||||
if (!dwt_enabled) EnableDWT();
|
||||
DWT_CYCCNT = 0; // zero counter value
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop code measure in this point
|
||||
* @param[out] micros Value in microseconds
|
||||
*/
|
||||
void StopCodeMeasure(u32_t *micros){
|
||||
if (!dwt_enabled){ *micros = 0; return; }
|
||||
//*micros = DWT_CYCCNT / SystemCoreClock; // get counter value
|
||||
*micros = DWT_CYCCNT; // get counter value
|
||||
}
|
||||
21
firmware/Libs/Utils/micros.h
Executable file
21
firmware/Libs/Utils/micros.h
Executable file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by enik on 07.03.2022.
|
||||
//
|
||||
|
||||
#ifndef _MICROS_H
|
||||
#define _MICROS_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libs.h"
|
||||
|
||||
void EnableDWT(void);
|
||||
void DelayMicros(u32_t val);
|
||||
void StartCodeMeasure(void);
|
||||
void StopCodeMeasure(u32_t *micros);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // _MICROS_H
|
||||
29
firmware/Libs/libs.h
Executable file
29
firmware/Libs/libs.h
Executable file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
*******************************************
|
||||
* @file libs.h
|
||||
* @author Dmitriy Semenov / Crazy_Geeks
|
||||
* @brief Internal header for adding sys libs and defines
|
||||
*******************************************
|
||||
*/
|
||||
|
||||
#ifndef LIBS_H_
|
||||
#define LIBS_H_
|
||||
|
||||
#include "main.h" ///< Main project file
|
||||
#include <stdlib.h> ///< Standard library
|
||||
#include <stdint.h> ///< Std types
|
||||
#include <stdbool.h> ///< _Bool to bool
|
||||
#include <string.h> ///< Lib for memcpy, strlen, etc
|
||||
#include <stdio.h> ///< Lib for sprintf, printf, etc
|
||||
|
||||
typedef uint8_t u8_t; ///< 8-bit unsigned
|
||||
typedef int8_t i8_t; ///< 8-bit signed
|
||||
typedef uint16_t u16_t; ///< 16-bit unsigned
|
||||
typedef int16_t i16_t; ///< 16-bit signed
|
||||
typedef uint32_t u32_t; ///< 32-bit unsigned
|
||||
typedef int32_t i32_t; ///< 32-bit signed
|
||||
typedef float fl_t; ///< float type
|
||||
|
||||
#define __USR_BKPT() __asm__ __volatile__("BKPT")
|
||||
|
||||
#endif /* LIBS_H_ */
|
||||
Reference in New Issue
Block a user