diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..703728a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "PenguinBuffer"] + path = PenguinBuffer + url = git@git.epenguin.net:penguin/PenguinBuffer.git diff --git a/Makefile b/Makefile index f2256f9..5e94df0 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,6 @@ Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart.c \ Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart_ex.c \ Core/Src/system_stm32l4xx.c \ shared/util/putil.c \ -shared/util/PCircularBuffer.c \ shared/drivers/p_serial_mgr.c \ shared/devices/motor_controller.c diff --git a/PenguinBuffer b/PenguinBuffer new file mode 160000 index 0000000..9804c4b --- /dev/null +++ b/PenguinBuffer @@ -0,0 +1 @@ +Subproject commit 9804c4b906262b873e7f72e3aab3bf899db34b64 diff --git a/motor_controller.ioc b/motor_controller.ioc index d7715c3..3f3c11b 100644 --- a/motor_controller.ioc +++ b/motor_controller.ioc @@ -1,16 +1,28 @@ #MicroXplorer Configuration settings - do not modify +Dma.Request0=USART1_RX +Dma.RequestsNb=1 +Dma.USART1_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART1_RX.0.Instance=DMA1_Channel5 +Dma.USART1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_RX.0.MemInc=DMA_MINC_ENABLE +Dma.USART1_RX.0.Mode=DMA_NORMAL +Dma.USART1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_RX.0.Priority=DMA_PRIORITY_LOW +Dma.USART1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority File.Version=6 KeepUserPlacement=false Mcu.CPN=STM32L432KCU3 Mcu.Family=STM32L4 -Mcu.IP0=NVIC -Mcu.IP1=RCC -Mcu.IP2=SYS -Mcu.IP3=TIM2 -Mcu.IP4=TIM6 -Mcu.IP5=USART1 -Mcu.IP6=USART2 -Mcu.IPNb=7 +Mcu.IP0=DMA +Mcu.IP1=NVIC +Mcu.IP2=RCC +Mcu.IP3=SYS +Mcu.IP4=TIM2 +Mcu.IP5=TIM6 +Mcu.IP6=USART1 +Mcu.IP7=USART2 +Mcu.IPNb=8 Mcu.Name=STM32L432K(B-C)Ux Mcu.Package=UFQFPN32 Mcu.Pin0=PC14-OSC32_IN (PC14) @@ -36,6 +48,7 @@ Mcu.UserName=STM32L432KCUx MxCube.Version=6.5.0 MxDb.Version=DB.6.0.50 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true +NVIC.DMA1_Channel5_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true @@ -129,7 +142,7 @@ ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=Makefile ProjectManager.ToolChainLocation= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_TIM2_Init-TIM2-false-HAL-true,4-MX_USART2_UART_Init-USART2-false-HAL-true,5-MX_TIM6_Init-TIM6-false-HAL-true,6-MX_USART1_UART_Init-USART1-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,4-MX_TIM2_Init-TIM2-false-HAL-true,5-MX_USART2_UART_Init-USART2-false-HAL-true,6-MX_DMA_Init-DMA-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true RCC.48CLKFreq_Value=24000000 RCC.AHBFreq_Value=32000000 RCC.APB1Freq_Value=32000000 diff --git a/shared/drivers/p_serial_mgr.c b/shared/drivers/p_serial_mgr.c index 8bb64ab..1867394 100644 --- a/shared/drivers/p_serial_mgr.c +++ b/shared/drivers/p_serial_mgr.c @@ -1,5 +1,4 @@ #include "p_serial_mgr.h" -#include "PCircularBuffer.h" #include "putil.h" #include "stm32l4xx_hal_uart.h" @@ -9,7 +8,7 @@ // [0]{1} Start delimiter 0x7E // [1]{1} Source Address // [2]{1} Destination Address -// [3]{1} Length Byte +// [3]{1} Length Byte (of non-delimited framebuffer) // [4-n]{n} frame data // [n+1]{1} checksum // Escape bytes are 0x7D, only frame data can be escaped @@ -18,38 +17,35 @@ typedef enum serial_state_t { - SS_IDLE = 0, // waiting - SS_START = 1, // get start byte, interrupt after 4 more bytes - SS_FRAME = 2, // get byte - SS_ESC = 3, // get byte, dont increment number left - SS_CHECKSUM = 4 // done + SS_IDLE = 0, // waiting + SS_START = 1, // get start byte, interrupt after 4 more bytes } serial_state_t; static UART_HandleTypeDef *_serial_huart_inst = NULL; static uint8_t rxc = '\0'; -static bool b_go = false; +static serial_state_t sstate = SS_IDLE; + void UART1_RxCpltCallback(UART_HandleTypeDef *huart) { - b_go = true; + if (rxc == 0x7E && sstate == SS_IDLE) + { + sstate = SS_START; + } } + void p_serial_mgr_init(UART_HandleTypeDef *huart) { _serial_huart_inst = huart; _serial_huart_inst->RxCpltCallback = UART1_RxCpltCallback; - b_go = false; } - -bool p_serial_mgr_service(void) +void p_serial_mgr_service(void) { - // // this will be less garbage when i switch to a queue - // for (int ind = 0; ind < serial_pkt_cb.max_len; ind++) - // { - // if (serial_pkt_cb.buffer[ind].b_ready) - // { - // return &serial_pkt_cb.buffer[ind]; - // } - // } + if (sstate == SS_START) + { + return; + } + else if (sstate = SS_IDLE) {} return b_go; } diff --git a/shared/drivers/p_serial_mgr.h b/shared/drivers/p_serial_mgr.h index 5a3b66b..f046861 100644 --- a/shared/drivers/p_serial_mgr.h +++ b/shared/drivers/p_serial_mgr.h @@ -4,14 +4,28 @@ #include "stm32l4xx_hal.h" #include +// start byte +// src_addr {1} + +// dest_addr {1} + +// frame_length {1} + +// checksum {1} + +// frame_data {510} -- making it 510 instead of 511 so it is easily divisible +#define MAX_MESSAGE_LEN (516) +#define MAX_FRAME_DATA_LEN (510) +// motor controller +#define DEVICE_ADDR (0x02) +// pi +#define MASTER_ADDR (0x01) + typedef struct serial_pkt_t { - uint8_t frame_data[256]; - uint8_t src_addr; - uint8_t dest_addr; - uint8_t checksum; - uint8_t len; - bool b_ready; + uint8_t *src_addr; + uint8_t *dest_addr; + uint8_t *frame_data_len; + uint8_t *checksum; + uint8_t *frame_data; + uint8_t data[MAX_MESSAGE_LEN]; + int msg_len; } serial_pkt_t; void p_serial_mgr_init(UART_HandleTypeDef *huart); diff --git a/shared/util/PCircularBuffer.c b/shared/util/PCircularBuffer.c deleted file mode 100644 index 121d6a9..0000000 --- a/shared/util/PCircularBuffer.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "putil.h" -#include - -// Error handler used for debugging only -#ifdef PB_CB_DEBUG -#include -static void handle_status(const char *func, PB_CB_STATUS status_code) -{ - if (status_code != PB_CB_GOOD) - { - PDEBUG("%s failed: error code: %d\r\n", func, status_code); - } -} -#endif - -// Circular Buffer Prototypes -- uint8_t -static PB_CB_STATUS p_cb_u8_push(p_cb_u8 *cbuffer, uint8_t value); -static PB_CB_STATUS p_cb_u8_empty(p_cb_u8 *cbuffer); - -// serial_pkt -static PB_CB_STATUS p_cb_serial_pkt_push(p_cb_serial_pkt_t *cbuffer, serial_pkt_t value); -static PB_CB_STATUS p_cb_serial_pkt_empty(p_cb_serial_pkt_t *cbuffer); - -// Circular Buffer Definitions -- uint8_t -PB_CB_STATUS p_cb_u8_init(p_cb_u8 *circ_buffer, uint8_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - // Make sure the buffer isn't bad (null) - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - // Make sure the max buffer is a useable size - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_u8_push(p_cb_u8 *cbuffer, uint8_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - } - else - { - cbuffer->buffer[cbuffer->head] = value; - cbuffer->head = (cbuffer->head + 1) % cbuffer->max_len; - } - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_u8_empty(p_cb_u8 *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - do - { - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - break; - } - - if (!cbuffer->buffer) - { - ret = PB_CB_NULL_BUFFER; - break; - } - memset(cbuffer->buffer, 0, cbuffer->max_len); - cbuffer->head = 0; - cbuffer->b_empty = true; - cbuffer->b_filled = false; - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -// Circular Buffer Definitions -- uint8_t -PB_CB_STATUS p_cb_serial_pkt_init(p_cb_serial_pkt_t *inst, serial_pkt_t *buff, uint32_t max_length) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - do - { - if (!buff) - { - ret = PB_CB_NULL_BUFFER; - break; - } - - if (max_length > PB_CB_MAX_BUFFER_SIZE || max_length <= 0) - { - ret = PB_CB_BAD_BUFFER_SIZE; - break; - } - for (int ind = 0; ind < max_length; ind++) - { - memset(inst->buffer[ind].frame_data, 0, 256); - } - inst->buffer = buff; - inst->max_len = (uint16_t)max_length; - inst->head = 0; - inst->push = p_cb_serial_pkt_push; - inst->empty = p_cb_serial_pkt_empty; - inst->empty(inst); - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_serial_pkt_push(p_cb_serial_pkt_t *cbuffer, serial_pkt_t value) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - } - else - { - cbuffer->buffer[cbuffer->head] = value; - cbuffer->head = (cbuffer->head + 1) % cbuffer->max_len; - } - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} - -PB_CB_STATUS p_cb_serial_pkt_empty(p_cb_serial_pkt_t *cbuffer) -{ - PB_CB_STATUS ret = PB_CB_GOOD; - - do - { - if (!cbuffer) - { - ret = PB_CB_NULL_CBUFFER; - break; - } - - if (!cbuffer->buffer) - { - ret = PB_CB_NULL_BUFFER; - break; - } - memset(cbuffer->buffer, 0, sizeof(serial_pkt_t) * cbuffer->max_len); - cbuffer->head = 0; - cbuffer->b_empty = true; - cbuffer->b_filled = false; - } while (0); - -// Debugging -#ifdef PB_CB_DEBUG - handle_status(__func__, ret); -#endif - - return ret; -} diff --git a/shared/util/PCircularBuffer.h b/shared/util/PCircularBuffer.h deleted file mode 100644 index 81797c5..0000000 --- a/shared/util/PCircularBuffer.h +++ /dev/null @@ -1,88 +0,0 @@ -// Resource/Inspiration: https://embedjournal.com/implementing-circular-buffer-embedded-c/ - -/* - Penguin's Circular Buffer -- a simple floating queue designed for low memory usage (mainly for embedded) - - This is a ring buffer with limited capabilities. It is meant as a container for moving data. - Normally included features such as checks to see if the buffer is full or empty have been omitted - because this type of buffer is being implemented mainly for sensor data usage. Data is almost never read - individually, and even if it is, it isn't meant to be cleared on read. It is a simple moving buffer that - automatically writes over old data for the purpose of keeping track of the most up to date data. - - Notes: - - Initialization is mandatory using p_cb__init. - - If a circular buffer is not initialized, you will run into a LOT of hard-to-debug problems. Just initialize it. - - By default, all cb types should be defined as disabled. This is to save on size. Enable the ones you want to use. - - Behavior: - - Oldest data is overwritten - - popping of data isn't implemented. If this feature is required, use a ring buffer. - - Acronyms: - - p: penguin - - pb: penguin buffer - - cb: circular buffer - - uX, where X is bit size: unsigned X bit integer - - iX, where X is bit size: signed X bit integer - - Note: I wrote this like 3 years ago or something. I hope it works. -*/ - -#ifndef _PCIRCULARBUFFER_H_ -#define _PCIRCULARBUFFER_H_ - -#include "p_serial_mgr.h" -#include -#include - -#ifdef _DEBUG -#define PC_CB_DEBUG -#endif - -// Max size is 65535 (2^16 - 1) so variables can be safely set 16 bits (unsigned) -// If you want to change this, you'll need to change the sizes of all heads and max lengths -#define PB_CB_MAX_BUFFER_SIZE (65535) - -typedef enum PB_CB_STATUS -{ - PB_CB_GOOD = 0, - PB_CB_BAD = 1, - PB_CB_BAD_BUFFER_SIZE = 2, - PB_CB_NULL_BUFFER = 3, - PB_CB_NULL_CBUFFER = 4 -} PB_CB_STATUS; - -typedef struct p_cb_u8 -{ - uint8_t *buffer; - uint16_t head; - uint16_t max_len; - // Signifies the buffer being filled at least once. - // Useful for initializing sensor data - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_u8 *cbuffer, uint8_t value); - PB_CB_STATUS (*empty)(struct p_cb_u8 *cbuffer); -} p_cb_u8; - -PB_CB_STATUS p_cb_u8_init(p_cb_u8 *circ_buffer, uint8_t *buff, uint32_t max_length); - -typedef struct p_cb_serial_pkt_t -{ - serial_pkt_t *buffer; - uint16_t head; - uint16_t max_len; - bool b_filled; - // Signifies the buffer being empty - // Useful for knowing if data is being received - bool b_empty; - - PB_CB_STATUS (*push)(struct p_cb_serial_pkt_t *cbuffer, serial_pkt_t value); - PB_CB_STATUS (*empty)(struct p_cb_serial_pkt_t *cbuffer); -} p_cb_serial_pkt_t; - -PB_CB_STATUS p_cb_serial_pkt_init(p_cb_serial_pkt_t *inst, serial_pkt_t *buff, uint32_t max_length); -#endif