diff --git a/components/f4ll_c/.gitrepo b/components/f4ll_c/.gitrepo new file mode 100644 index 0000000..631c870 --- /dev/null +++ b/components/f4ll_c/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = git@git.pcmuhely.hu:compi/f4ll_c.git + branch = master + commit = 7570c78a802a8a9300e9747beda701cc8f7e16c1 + parent = 9f225a2c9da2182935f989e7db7e82d9dcffeed7 + method = merge + cmdver = 0.4.0 diff --git a/components/f4ll_c/component.mk b/components/f4ll_c/component.mk new file mode 100644 index 0000000..ebed01c --- /dev/null +++ b/components/f4ll_c/component.mk @@ -0,0 +1,10 @@ +#encoder +SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +REL_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +ifeq ($(MKDBG), 1) + $(info >>> $(REL_DIR)/component.mk) +endif +$(eval C_SOURCES += $(wildcard $(REL_DIR)/*.c)) +ifeq ($(MKDBG), 1) + $(info <<<) +endif diff --git a/components/f4ll_c/consolehandler.c b/components/f4ll_c/consolehandler.c new file mode 100644 index 0000000..7b6e944 --- /dev/null +++ b/components/f4ll_c/consolehandler.c @@ -0,0 +1,68 @@ +/* + * interrupt.c + * + * Created on: Aug 29, 2019 + * Author: abody + */ +#include "main.h" +#include "globals.h" +#include "f4ll_c/packetusart.h" +#include "f4ll_c/strutil.h" + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +void Con_HandleTxDmaIrq(DMAINFO *info, USART_TypeDef *usart) // debug usart +{ + DIAG_INTERRUPT_IN(); + if(*info->isReg & info->tcMask) { // DMA transfer complete + *info->ifcReg = info->tcMask; + LL_USART_EnableIT_TC(usart); + LL_DMA_DisableStream(info->dma, info->stream); + } + DIAG_INTERRUPT_OUT(); +} + +void Con_HandleUsartIrq(USART_TypeDef *usart) +{ + DIAG_INTERRUPT_IN(); + if(LL_USART_IsActiveFlag_TC(usart) && LL_USART_IsEnabledIT_TC(usart)) // transmission complete + LL_USART_DisableIT_TC(usart); + DIAG_INTERRUPT_OUT(); +} + +#define ADDINFO(b,s,u) \ + b += strcpy_ex(b,s); \ + b += uitodec(b,u); + +void Con_PrintStats(char *buffer, uint8_t id, struct usart_stats *stats, USART_TypeDef *usart, DMAINFO *dmaInfo) +{ + char ids[] = " : "; + char *bs = buffer; + + ids[0] = id + '0'; + buffer += strcpy_ex(buffer, ids); + ADDINFO(buffer, " s: ", stats->sent); + ADDINFO(buffer, " r: ", stats->rcvd); + ADDINFO(buffer, " sk: ", stats->skiped); + ADDINFO(buffer, " or: ", stats->overrun); + ADDINFO(buffer, " he: ", stats->hdrError); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->lastErrHdr, 8); + ADDINFO(buffer, " pe: ", stats->payloadErrror); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->pep1, 8); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->pep2, 8); + ADDINFO(buffer, " de: ", stats->dmaError); + ADDINFO(buffer, " pmh: ", stats->premature_hdr); + ADDINFO(buffer, " pmp: ", stats->premature_payload); + buffer += strcpy_ex(buffer, "\r\n"); + + Pku_SetupTransmit(usart, dmaInfo->dma, dmaInfo->stream, bs, buffer - bs + 1); +} diff --git a/components/f4ll_c/consolehandler.h b/components/f4ll_c/consolehandler.h new file mode 100644 index 0000000..cbb9207 --- /dev/null +++ b/components/f4ll_c/consolehandler.h @@ -0,0 +1,20 @@ +/* + * interrupt.h + * + * Created on: Aug 29, 2019 + * Author: abody + */ + +#ifndef INTERRUPT_HANDLERS_H_ +#define INTERRUPT_HANDLERS_H_ + +#include "usart.h" +#include "f4ll_c/dmahelper.h" +#include "f4ll_c/packetusart.h" + +void Con_HandleTxDmaIrq(DMAINFO *info, USART_TypeDef *usart); +void Con_HandleUsartIrq(USART_TypeDef *usart); + +void Con_PrintStats(char *buffer, uint8_t id, struct usart_stats *stats, USART_TypeDef *usart, DMAINFO *dmaInfo); + +#endif /* INTERRUPT_HANDLERS_H_ */ diff --git a/components/f4ll_c/crcscheduler.c b/components/f4ll_c/crcscheduler.c new file mode 100644 index 0000000..87d4d45 --- /dev/null +++ b/components/f4ll_c/crcscheduler.c @@ -0,0 +1,179 @@ +/* + * interrupt.c + * + * Created on: Aug 29, 2019 + * Author: abody + */ +#include +#include "main.h" +#include +#include +#include "diag.h" +#include "f4ll_c/dmahelper.h" + +#ifndef DIAG_CRC_CALC_START +# define DIAG_CRC_CALC_START() +#endif + +#ifndef DIAG_CRC_CALC_END +# define DIAG_CRC_CALC_END() +#endif + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +void Crc_InitStatus(struct crcstatus_t *st, DMA_TypeDef *dma, uint32_t stream) +{ + Dma_Init(&st->dmaInfo, dma, stream); + LL_DMA_EnableIT_TC(dma, stream); + LL_DMA_EnableIT_TE(dma, stream); + LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&CRC->DR); + st->activeSlot = NULL; + st->first = NULL; +} + +void Crc_AttachTask(struct crcstatus_t *status, struct crcslotlistitem_t *slot, struct crcslottask_t *tasks, uint8_t taskCount) +{ + slot->count = taskCount; + slot->tasks = tasks; + memset(tasks, 0, sizeof(*tasks)*taskCount); + + uint32_t prim = __get_PRIMASK(); + __disable_irq(); + slot->next = status->first; + status->first = slot; + __set_PRIMASK(prim); +} + +uint8_t Crc_GetActiveTask(struct crcslotlistitem_t **slot_out, struct crcstatus_t volatile *status) +{ + uint8_t ret; + + uint32_t prim = __get_PRIMASK(); + + __disable_irq(); + ret = status->activeTask; + if(slot_out) + *slot_out = (struct crcslotlistitem_t *) status->activeSlot; + __set_PRIMASK(prim); + return ret; +} + + +uint8_t Crc_Enqueue(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, + uint8_t *address, uint16_t len, void (*callback)(void*, uint32_t, uint8_t), void* callbackParam) +{ + uint32_t prim = __get_PRIMASK(); + uint16_t need_start; + struct crcstatus_t volatile *st = status; + + while(st->activeSlot == slot && st->activeTask == task); + __disable_irq(); + need_start = (st->activeSlot == NULL); + slot->tasks[task].address = need_start ? NULL : address; + slot->tasks[task].wordCount = (len+3)/4; + slot->tasks[task].callback = callback; + slot->tasks[task].callbackParam = callbackParam; + if(need_start) { + status->activeSlot = slot; + status->activeTask = task; + } + __set_PRIMASK(prim); + + if(need_start) { + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(status->dmaInfo.dma, status->dmaInfo.stream, (uint32_t)address); + LL_DMA_SetDataLength(status->dmaInfo.dma, status->dmaInfo.stream, (len+3)/4); + DIAG_CRC_CALC_START(); + LL_DMA_EnableStream(status->dmaInfo.dma, status->dmaInfo.stream); + } + return need_start; +} + +void Crc_WaitResults(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task) +{ + struct crcslotlistitem_t *slotQueued; + + while(Crc_IsSlotQueued(slot, task)); + while(Crc_GetActiveTask(&slotQueued, status) == task && slotQueued == slot); +} + + +uint32_t Crc_Compute(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, uint8_t *address, uint16_t len) +{ + uint32_t result; + Crc_Enqueue(status, slot, task, address, len, NULL, &result); + while((struct crcslotlistitem_t volatile *)slot->tasks[task].callbackParam); + return result; +} + +// only called from ISR context +static void StartNextCrcTask(struct crcstatus_t *status) +{ + char moreTasks; + uint8_t index = 0; + + do { + struct crcslotlistitem_t *slot = status->first; + moreTasks = 0; + while(slot) { + if(index < slot->count) { + if(slot->tasks[index].address) { + status->activeSlot = slot; + status->activeTask = index; + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(status->dmaInfo.dma, status->dmaInfo.stream, (uint32_t)slot->tasks[index].address); + LL_DMA_SetDataLength(status->dmaInfo.dma, status->dmaInfo.stream, slot->tasks[index].wordCount); + LL_DMA_EnableStream(status->dmaInfo.dma, status->dmaInfo.stream); + slot->tasks[index].address = NULL; // marking as started + return; + } + if(index + 1 < slot->count) + moreTasks = 1; + } + slot = slot->next; + } + ++index; + } while(moreTasks); + status->activeSlot = NULL; +} + +void Crc_HandleDmaIrq(struct crcstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(*status->dmaInfo.isReg & status->dmaInfo.tcMask) { // DMA transfer complete + *status->dmaInfo.ifcReg = status->dmaInfo.tcMask; + LL_DMA_DisableStream(status->dmaInfo.dma, status->dmaInfo.stream); + if(status->activeSlot) { + struct crcslottask_t *tsk = &status->activeSlot->tasks[status->activeTask]; + if(tsk->callback) + tsk->callback(tsk->callbackParam, CRC->DR, 1); + else if(tsk->callbackParam) + *(uint32_t*)tsk->callbackParam = CRC->DR; + tsk->callback = tsk->callbackParam = NULL; // marking as inactive + DIAG_CRC_CALC_END(); + StartNextCrcTask(status); + } + } + else if(*status->dmaInfo.isReg & status->dmaInfo.teMask) { + *status->dmaInfo.ifcReg = status->dmaInfo.teMask; + LL_DMA_DisableStream(status->dmaInfo.dma, status->dmaInfo.stream); + if(status->activeSlot) { + struct crcslottask_t *tsk = &status->activeSlot->tasks[status->activeTask]; + if(tsk->callback) + tsk->callback(tsk->callbackParam, CRC->DR, 0); + else if(tsk->callbackParam) + *(uint32_t*)tsk->callbackParam = 0xffffffff; + tsk->callback = tsk->callbackParam = NULL; // marking as inactive + DIAG_CRC_CALC_END(); + StartNextCrcTask(status); + } + } + DIAG_INTERRUPT_OUT(); +} + diff --git a/components/f4ll_c/crcscheduler.h b/components/f4ll_c/crcscheduler.h new file mode 100644 index 0000000..b82a1e0 --- /dev/null +++ b/components/f4ll_c/crcscheduler.h @@ -0,0 +1,62 @@ +/* + * interrupt.h + * + * Created on: Aug 29, 2019 + * Author: abody + */ + +#ifndef CRC_HANDLER_H_ +#define CRC_HANDLER_H_ + +#include + +#ifdef HAVE_CONFIG +#include "config.h" +#endif // HAVE_CONFIG + +#include + +struct crcslottask_t { + void * volatile address; + uint16_t wordCount; + void (*callback)(void*, uint32_t, uint8_t); + void *callbackParam; +}; + +struct crcslotlistitem_t { + uint16_t count; + struct crcslotlistitem_t *next; + struct crcslottask_t *tasks; +}; + +struct crcstatus_t { + DMAINFO dmaInfo; + struct crcslotlistitem_t *activeSlot; + uint8_t activeTask; + struct crcslotlistitem_t *first; +}; + +void Crc_InitStatus(struct crcstatus_t *status, DMA_TypeDef *dma, uint32_t stream); + +uint8_t Crc_GetActiveTask(struct crcslotlistitem_t **slot_out, struct crcstatus_t volatile *status); + +static inline uint8_t Crc_IsSlotQueued(struct crcslotlistitem_t volatile *slot, uint8_t task) { + return slot->tasks[task].address != NULL; +} + +static inline uint8_t Crc_IsSlotActive(struct crcslotlistitem_t volatile *slot, uint8_t task) { + return slot->tasks[task].callback != NULL || slot->tasks[task].callbackParam != NULL; +} + +void Crc_AttachTask(struct crcstatus_t *status, struct crcslotlistitem_t *slot, struct crcslottask_t *tasks, uint8_t taskCount); + +uint8_t Crc_Enqueue(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, + uint8_t *address, uint16_t len, void (*callback)(void*, uint32_t, uint8_t), void* callbackParam); +void Crc_WaitResults(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task); +uint32_t Crc_Compute(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, uint8_t *address, uint16_t len); +void Crc_ComputeAsync(struct crcstatus_t *status, uint8_t slot, + uint8_t *address, uint16_t len, + void (*callback)(void*, uint32_t, uint8_t), void* callbackParam); +void Crc_HandleDmaIrq(struct crcstatus_t *status); + +#endif /* CRC_HANDLER_H_ */ diff --git a/components/f4ll_c/dmahelper.c b/components/f4ll_c/dmahelper.c new file mode 100644 index 0000000..b516d43 --- /dev/null +++ b/components/f4ll_c/dmahelper.c @@ -0,0 +1,78 @@ +/* + * dma_helper.c + * + * Created on: Sep 18, 2019 + * Author: abody + */ +#include + + +volatile uint32_t* Dma_GetIsReg(DMA_TypeDef *dma, uint32_t stream) +{ + if(dma == DMA1) + return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR; + else + return (stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR; +} + +volatile uint32_t* Dma_GetIfcReg(DMA_TypeDef *dma, uint32_t stream) +{ + if(dma == DMA1) + return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR; + else + return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR; +} + +uint32_t Dma_GetFeMask(uint32_t stream) +{ + static const uint32_t feMasks[8] = { + DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7 + }; + return feMasks[stream]; +} + +uint32_t Dma_GetDmeMask(uint32_t stream) +{ + static const uint32_t dmeMasks[8] = { + DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7 + }; + return dmeMasks[stream]; +} + +uint32_t Dma_GetTeMask(uint32_t stream) +{ + static const uint32_t teMasks[8] = { + DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7 + }; + return teMasks[stream]; +} + +uint32_t Dma_GetHtMask(uint32_t stream) +{ + static const uint32_t htMasks[8] = { + DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7 + }; + return htMasks[stream]; +} + +uint32_t Dma_GetTcMask(uint32_t stream) +{ + static const uint32_t tcMasks[8] = { + DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7 + }; + + return tcMasks[stream]; +} + +void Dma_Init(DMAINFO *info, DMA_TypeDef *dma, uint32_t stream) +{ + info->dma = dma; + info->stream = stream; + info->isReg = Dma_GetIsReg(dma, stream); + info->ifcReg = Dma_GetIfcReg(dma, stream); + info->feMask = Dma_GetFeMask(stream); + info->dmeMask = Dma_GetDmeMask(stream); + info->teMask = Dma_GetTeMask(stream); + info->htMask = Dma_GetHtMask(stream); + info->tcMask = Dma_GetTcMask(stream); +} diff --git a/components/f4ll_c/dmahelper.h b/components/f4ll_c/dmahelper.h new file mode 100644 index 0000000..d54e22c --- /dev/null +++ b/components/f4ll_c/dmahelper.h @@ -0,0 +1,35 @@ +/* + * dma_helper.h + * + * Created on: Sep 18, 2019 + * Author: abody + */ + +#ifndef DMA_HELPER_H_ +#define DMA_HELPER_H_ +#include +#include + +typedef struct { + DMA_TypeDef *dma; + uint32_t stream; + volatile uint32_t *isReg; + volatile uint32_t *ifcReg; + uint32_t feMask; + uint32_t dmeMask; + uint32_t teMask; + uint32_t htMask; + uint32_t tcMask; +} DMAINFO; + +volatile uint32_t* Dma_GetIsReg(DMA_TypeDef *dma, uint32_t stream); +volatile uint32_t* Dma_GetIfcReg(DMA_TypeDef *dma, uint32_t stream); +uint32_t Dma_GetDmeMask(uint32_t stream); +uint32_t Dma_GetTeMask(uint32_t stream); +uint32_t Dma_GetHtMask(uint32_t stream); +uint32_t Dma_GetTcMask(uint32_t stream); +uint32_t Dma_GetFeMask(uint32_t stream); + +void Dma_Init(DMAINFO *info, DMA_TypeDef *dma, uint32_t stream); + +#endif /* DMA_HELPER_H_ */ diff --git a/components/f4ll_c/f4ll_c b/components/f4ll_c/f4ll_c new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/components/f4ll_c/f4ll_c @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/components/f4ll_c/memcpydma.c b/components/f4ll_c/memcpydma.c new file mode 100644 index 0000000..68b725e --- /dev/null +++ b/components/f4ll_c/memcpydma.c @@ -0,0 +1,48 @@ +/* + * memcpy_dma.c + * + * Created on: Oct 1, 2019 + * Author: abody + */ +#include +#include + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +volatile uint8_t g_memcpyDmaBusy = 0; + +static DMAINFO g_memcpyDmaInfo; + +void Mcd_Init(DMA_TypeDef *dma, uint32_t stream) +{ + Dma_Init(&g_memcpyDmaInfo, dma, stream); + LL_DMA_EnableIT_TC(dma, stream); +} + +void * Mcd_Copy(void *dst, void const *src, size_t length) +{ + LL_DMA_SetM2MSrcAddress(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (uint32_t)src); + LL_DMA_SetM2MDstAddress(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (uint32_t)dst); + LL_DMA_SetDataLength(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (length+3)/4 ); + g_memcpyDmaBusy = 1; + LL_DMA_EnableStream(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream); + while(g_memcpyDmaBusy); + return dst; +} + +void Mcd_HandleDmaIrq() +{ + DIAG_INTERRUPT_IN(); + if(*g_memcpyDmaInfo.isReg & g_memcpyDmaInfo.tcMask) { // DMA transfer complete + *g_memcpyDmaInfo.ifcReg = g_memcpyDmaInfo.tcMask; + LL_DMA_DisableStream(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream); + g_memcpyDmaBusy = 0; + } + DIAG_INTERRUPT_OUT(); +} diff --git a/components/f4ll_c/memcpydma.h b/components/f4ll_c/memcpydma.h new file mode 100644 index 0000000..b67573e --- /dev/null +++ b/components/f4ll_c/memcpydma.h @@ -0,0 +1,18 @@ +/* + * memcpy_dma.h + * + * Created on: Oct 1, 2019 + * Author: abody + */ + +#ifndef MEMCPY_DMA_H_ +#define MEMCPY_DMA_H_ + +#include +#include + +void Mcd_Init(DMA_TypeDef *dma, uint32_t stream); +void * Mcd_Copy(void *dst, void const *src, size_t length); +void Mcd_HandleDmaIrq(); + +#endif /* MEMCPY_DMA_H_ */ diff --git a/components/f4ll_c/packetusart.c b/components/f4ll_c/packetusart.c new file mode 100644 index 0000000..4f10d42 --- /dev/null +++ b/components/f4ll_c/packetusart.c @@ -0,0 +1,265 @@ +/* + * usart_handler.c + * + * Created on: Sep 16, 2019 + * Author: abody + */ + +#include +#include +#include +#include +#include "diag.h" +#include "f4ll_c/dmahelper.h" +#include "f4ll_c/crcscheduler.h" + +#ifndef DIAG_RX_BUFFER_SWITCH +# define DIAG_RX_BUFFER_SWITCH(x) +#endif +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +#define STARTMARKER 0x95 + +static inline uint32_t RoundUpTo4(uint32_t inp) +{ + return (inp + 3) & 0xfffc; +} + +void Pku_Init( + struct usartstatus_t *st, USART_TypeDef *usart, DMA_TypeDef *dma, + uint32_t stream_rx, uint32_t stream_tx, + struct crcstatus_t *crcStatus, + pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam) +{ + uint32_t status = usart->SR; + volatile uint32_t tmpreg = usart->DR; // clearing some of the error/status bits in the USART + (void) tmpreg; + (void) status; + + st->usart = usart; + Dma_Init(&st->rxDmaInfo, dma, stream_rx); + Dma_Init(&st->txDmaInfo, dma, stream_tx); + st->txBuffer.busy = 0; + st->txBuffer.error = 0; + st->txBuffer.requestedLength = 0; + st->rxBuffers[0].busy = 0; + st->rxBuffers[1].busy = 0; + st->rxBuffers[0].error = 0; + st->rxBuffers[1].error = 0; + st->rxBuffers[0].requestedLength = 0; + st->rxBuffers[1].requestedLength = 0; + st->txBuffer.usartStatus = st; + st->rxBuffers[0].usartStatus = st; + st->rxBuffers[1].usartStatus = st; + st->packetReceivedCallback = packetReceivedCallback; + st->packetReceivedCallbacParam = packetReceivedCallbackParam; + st->rxSerial = -1; + st->txSerial = 0; + st->activeRxBuf = 0; + st->crcStatus = crcStatus; + Crc_AttachTask(crcStatus, &st->crcSlot, st->crcTasks, 2); + memset(&st->stats, 0, sizeof(st->stats)); + + *Dma_GetIfcReg(dma, stream_rx) = + Dma_GetTcMask(stream_rx) | Dma_GetHtMask(stream_rx) | + Dma_GetTeMask(stream_rx) | Dma_GetFeMask(stream_rx) | Dma_GetDmeMask(stream_rx); + *Dma_GetIfcReg(dma, stream_tx) = + Dma_GetTcMask(stream_tx) | Dma_GetHtMask(stream_tx) | + Dma_GetTeMask(stream_tx) | Dma_GetFeMask(stream_tx) | Dma_GetDmeMask(stream_tx); + + LL_DMA_EnableIT_TC(dma, stream_rx); + LL_DMA_EnableIT_TE(dma, stream_rx); + LL_DMA_EnableIT_TC(dma, stream_tx); + LL_DMA_EnableIT_TE(dma, stream_tx); + LL_USART_EnableIT_IDLE(usart); +} + + +uint8_t* Pku_GetTxBuffer(struct usartstatus_t *status) +{ + return status->txBuffer.packet.payload; +} + + +static inline void BuildHeader(struct usart_buffer_t *buffer, uint8_t serial, uint8_t length) +{ + uint8_t hash = STARTMARKER; + buffer->packet.header.startByte = STARTMARKER; + buffer->packet.header.serial = serial; + hash ^= serial; + buffer->packet.header.payloadLength = length - 1; + hash ^= length - 1; + buffer->packet.header.hash = hash; +} + +static inline uint8_t CheckHeader(struct usartpacket_t *packet) +{ + return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash; +} + + +uint8_t Pku_Post(struct usartstatus_t *status, uint8_t const *payload, uint16_t length, struct crcstatus_t *crcStatus, uint8_t waitForCrcQueue) +{ +// static uint32_t count = 0; +// ITM->PORT[1].u32 = count++; + + if(length > 256) + return 1; + + + BuildHeader(&status->txBuffer, status->txSerial++, length); + uint16_t payloadLength = RoundUpTo4(length); + if(payload) + memcpy(status->txBuffer.packet.payload, payload, length); + status->txBuffer.requestedLength = sizeof(struct usartpacketheader_t) + payloadLength + sizeof(uint32_t); // +4 for the hash + status->txBuffer.busy = 1; + status->txBuffer.error = 0; + Crc_Enqueue(status->crcStatus, &status->crcSlot, 0, status->txBuffer.packet.payload, length, + NULL, (uint32_t*)(status->txBuffer.packet.payload + payloadLength)); + while(waitForCrcQueue && Crc_IsSlotQueued(&status->crcSlot, 0)); + Pku_SetupTransmit(status->usart, status->txDmaInfo.dma, status->txDmaInfo.stream, &status->txBuffer.packet, status->txBuffer.requestedLength); + + StatsIncSent(&status->stats); + return 0; +} + + +void Pku_SetupReceive(struct usartstatus_t *status) +{ + uint8_t packetIndex = status->activeRxBuf; + + LL_DMA_ConfigAddresses(status->rxDmaInfo.dma, status->rxDmaInfo.stream, LL_USART_DMA_GetRegAddr(status->usart), (uint32_t)&status->rxBuffers[packetIndex], + LL_DMA_DIRECTION_PERIPH_TO_MEMORY); + status->rxBuffers[packetIndex].requestedLength = sizeof(status->rxBuffers[packetIndex].packet); + LL_DMA_SetDataLength(status->rxDmaInfo.dma, status->rxDmaInfo.stream, status->rxBuffers[packetIndex].requestedLength); // payload already have extra room for hash + LL_USART_EnableDMAReq_RX(status->usart); + LL_USART_ClearFlag_ORE(status->usart); + LL_DMA_EnableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); +} + + +void Pku_ConsumePacket(struct usartstatus_t *status, uint8_t packetIndex) +{ + struct usart_buffer_t *buffer = &status->rxBuffers[packetIndex]; + if(buffer->busy) { + if(buffer->error) + StatsIncPayloadError(&status->stats, buffer->errorInfo, *(uint32_t*) (buffer->packet.payload + RoundUpTo4(buffer->packet.header.payloadLength + 1))); + else { + uint8_t diff = buffer->packet.header.serial - status->rxSerial; + if(diff > 1) + StatsAddSkiped(&status->stats, diff - 1); + status->rxSerial = buffer->packet.header.serial; + } + } + + buffer->busy = buffer->error = 0; +} + + +void Pku_SetupTransmit(USART_TypeDef *usart, DMA_TypeDef* dma, uint32_t stream, void *buffer, uint32_t length) +{ + LL_DMA_ConfigAddresses(dma, stream, (uint32_t)buffer, LL_USART_DMA_GetRegAddr(usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); + LL_DMA_SetDataLength(dma, stream, length); + LL_USART_EnableDMAReq_TX(usart); + LL_DMA_EnableStream(dma, stream); +} + +void RxCrcComputedCallback(void *callbackParm, uint32_t calculatedCrc, uint8_t success) +{ + struct usart_buffer_t *ub = (struct usart_buffer_t*) callbackParm; + if(!success) + ub->error = 1; + else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength + 1)) == calculatedCrc) + ub->busy = 1; + else { + ub->error = ub->busy = 1; + ub->errorInfo = calculatedCrc; + } + if(ub->usartStatus->packetReceivedCallback) + ub->usartStatus->packetReceivedCallback(ub->usartStatus->packetReceivedCallbacParam, ub); +} + +void Pku_HandleRxDmaIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + StatsIncRcvd(&status->stats); + if(*status->rxDmaInfo.isReg & status->rxDmaInfo.tcMask) { + *status->rxDmaInfo.ifcReg = status->rxDmaInfo.tcMask; + if(CheckHeader(&status->rxBuffers[status->activeRxBuf].packet)) + Crc_Enqueue(status->crcStatus, &status->crcSlot, 1, + status->rxBuffers[status->activeRxBuf].packet.payload, + status->rxBuffers[status->activeRxBuf].packet.header.payloadLength +1, + RxCrcComputedCallback, &status->rxBuffers[status->activeRxBuf]); + else { + StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header); + status->rxBuffers[status->activeRxBuf].error = 1; + } + } else if(*status->rxDmaInfo.isReg & status->rxDmaInfo.teMask) { + *status->rxDmaInfo.ifcReg = status->rxDmaInfo.teMask; + status->rxBuffers[status->activeRxBuf].error = 1; + } + + status->activeRxBuf ^= 1; + + DIAG_RX_BUFFER_SWITCH(status->activeRxBuf); + if(status->rxBuffers[status->activeRxBuf].busy) + StatsIncOverrun(&status->stats); + Pku_SetupReceive(status); + DIAG_INTERRUPT_OUT(); +} + +void Pku_HandleTxDmaIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(*status->txDmaInfo.isReg & status->txDmaInfo.tcMask) { // DMA transfer complete + *status->txDmaInfo.ifcReg = status->txDmaInfo.tcMask; + LL_USART_EnableIT_TC(status->usart); + LL_DMA_DisableStream(status->txDmaInfo.dma, status->txDmaInfo.stream); + } + else if(*status->txDmaInfo.isReg & status->txDmaInfo.teMask) { + *status->txDmaInfo.ifcReg = status->txDmaInfo.teMask; + status->txBuffer.error = 1; + StatsIncDmaError(&status->stats); + } + if(*status->txDmaInfo.isReg & status->txDmaInfo.feMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.feMask; + if(*status->txDmaInfo.isReg & status->txDmaInfo.htMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.htMask; + if(*status->txDmaInfo.isReg & status->txDmaInfo.dmeMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.dmeMask; + DIAG_INTERRUPT_OUT(); +} + +void Pku_HandleUsartIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(LL_USART_IsActiveFlag_IDLE(status->usart) && LL_USART_IsEnabledIT_IDLE(status->usart)) { // receiver idle + LL_USART_ClearFlag_IDLE(status->usart); + uint16_t rcvdLen = status->rxBuffers[status->activeRxBuf].requestedLength - LL_DMA_GetDataLength(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + if(rcvdLen >= sizeof(struct usartpacketheader_t)) { + if(CheckHeader(&status->rxBuffers[status->activeRxBuf].packet)) { + if(rcvdLen >= sizeof(struct usartpacketheader_t) + RoundUpTo4(status->rxBuffers[status->activeRxBuf].packet.header.payloadLength + 1) + sizeof(uint32_t)) + LL_DMA_DisableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + else + StatsIncPremature_payload(&status->stats); + } else { + status->rxBuffers[status->activeRxBuf].error = 1; + LL_DMA_DisableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + } + } else + StatsIncPremature_hdr(&status->stats); + } + else if(LL_USART_IsActiveFlag_TC(status->usart) && LL_USART_IsEnabledIT_TC(status->usart)) { // transmission complete + LL_USART_DisableIT_TC(status->usart); + LL_USART_DisableDirectionTx(status->usart); // enforcing an idle frame + LL_USART_EnableDirectionTx(status->usart); + status->txBuffer.busy = 0; + } + DIAG_INTERRUPT_OUT(); +} + diff --git a/components/f4ll_c/packetusart.h b/components/f4ll_c/packetusart.h new file mode 100644 index 0000000..c980a8b --- /dev/null +++ b/components/f4ll_c/packetusart.h @@ -0,0 +1,142 @@ +/* + * usart_handler.h + * + * Created on: Sep 16, 2019 + * Author: abody + */ + +#ifndef USART_HANDLER_H_ +#define USART_HANDLER_H_ +#include +#include + +#include "f4ll_c/dmahelper.h" + +struct usart_buffer_t; +struct usartstatus_t; + +typedef void (*pku_packetreceivedcallback_t)(void *userParam, struct usart_buffer_t *buffer); + +void Pku_Init( + struct usartstatus_t *st, USART_TypeDef *usart, DMA_TypeDef *dma, + uint32_t stream_rx, uint32_t stream_tx, + struct crcstatus_t *crcStatus, + pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam); + +uint8_t* Pku_GetTxBuffer(struct usartstatus_t *status); + +uint8_t Pku_Post(struct usartstatus_t *status, uint8_t const *payload, uint16_t length, struct crcstatus_t *crcStatus, uint8_t waitForCrcQueue); +void Pku_SetupReceive(struct usartstatus_t *status); +void Pku_SetupTransmit(USART_TypeDef *usart, DMA_TypeDef* dma, uint32_t stream, void *buffer, uint32_t length); +void Pku_ConsumePacket(struct usartstatus_t *status, uint8_t packetIndex); + +void Pku_HandleRxDmaIrq(struct usartstatus_t *status); +void Pku_HandleTxDmaIrq(struct usartstatus_t *status); +void Pku_HandleUsartIrq(struct usartstatus_t *status); + +/****************************************************************************************** + * + * + * + */ + +struct usart_stats { + uint32_t overrun; + uint32_t hdrError; + uint32_t lastErrHdr; + uint32_t payloadErrror; + uint32_t pep1, pep2; + uint32_t dmaError; + uint32_t rcvd; + uint32_t premature_hdr; + uint32_t premature_payload; + uint32_t sent; + uint32_t skiped; +}; + +struct usartpacketheader_t { + uint8_t startByte; + uint8_t serial; + uint8_t payloadLength; + uint8_t hash; +}; + +struct usartpacket_t { + struct usartpacketheader_t header; + //!!! should start on word offset !!! + uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32 +} __attribute__((aligned)); + +struct usart_buffer_t { + struct usartpacket_t packet; + //transfer area ends here + volatile uint8_t busy; + volatile uint8_t error; + uint16_t requestedLength; + uint32_t errorInfo; + struct usartstatus_t *usartStatus; +}; + +struct usartstatus_t { + USART_TypeDef *usart; + DMAINFO rxDmaInfo; + DMAINFO txDmaInfo; + struct crcstatus_t *crcStatus; + struct crcslotlistitem_t crcSlot; + struct crcslottask_t crcTasks[2]; + + uint8_t rxSerial; + uint8_t txSerial; + struct usart_stats stats; + uint8_t activeRxBuf; + pku_packetreceivedcallback_t packetReceivedCallback; + void *packetReceivedCallbacParam; + struct usart_buffer_t txBuffer; + struct usart_buffer_t rxBuffers[2]; +}; + +#ifndef USART_STATS_DISABLED +static inline void StatsIncOverrun(struct usart_stats *s) { + ++s->overrun; +} +static inline void StatsIncHdrError(struct usart_stats *s, uint32_t hdr) { + ++s->hdrError; + s->lastErrHdr = hdr; +} +static inline void StatsIncPayloadError(struct usart_stats *s, uint32_t pep1, uint32_t pep2) { + ++s->payloadErrror; + s->pep1 = pep1; + s->pep2 = pep2; +} +static inline void StatsIncDmaError(struct usart_stats *s) { + ++s->dmaError; +} +static inline void StatsIncRcvd(struct usart_stats *s) { + ++s->rcvd; +} +static inline void StatsIncPremature_hdr(struct usart_stats *s) { + ++s->premature_hdr; +} +static inline void StatsIncPremature_payload(struct usart_stats *s) { + ++s->premature_payload; +} +static inline void StatsIncSent(struct usart_stats *s) { + ++s->sent; +} +static inline void StatsAddSkiped(struct usart_stats *s, uint8_t cnt) { + s->skiped += s->rcvd > 2 ? cnt : 0; +} + +#else // USART_STATS_DISABLED +#define StatsIncOverrun(x) +#define StatsIncHdrError(x,y) +#define StatsIncPayloadError(x,y,z) +#define StatsIncDmaError(x) +#define StatsIncRcvd(x) +#define StatsIncPremature_hdr(x) +#define StatsIncPremature_payload(x) +#define StatsIncSent(x) +#define StatsAddSkiped(x) +#endif // USART_STATS_DISABLED + +#endif /* UART_HANDLER_H_ */ diff --git a/components/f4ll_c/strutil.c b/components/f4ll_c/strutil.c new file mode 100644 index 0000000..c41e16e --- /dev/null +++ b/components/f4ll_c/strutil.c @@ -0,0 +1,110 @@ +#include +#include "f4ll_c/strutil.h" + +////////////////////////////////////////////////////////////////////////////// +size_t strcpy_ex(char *dst, char const *src) +{ + size_t ret = 0; + do { + *dst++ = *src; + ++ret; + } while(*src++); + return ret - 1; +} + +////////////////////////////////////////////////////////////////////////////// +void strrev(char *first, char *last) +{ + char tmp; + while(last > first) { + tmp = *first; + *first++ = *last; + *last-- = tmp; + } +} + +////////////////////////////////////////////////////////////////////////////// +char tochr(const uint8_t in, const uint8_t upper) +{ + return in + ((in < 10) ? '0' : (upper ? 'A' : 'a') - 10); +} + +////////////////////////////////////////////////////////////////////////////// +size_t uitodec(char* buffer, uint32_t data) +{ + char *b2 = buffer; + if(!data) { + *b2++ = '0'; + *b2 = '\0'; + return 1; + } + + while(data) { + *b2++ = (data % 10) + '0'; + data /= 10; + } + size_t ret = b2 - buffer; + + *b2-- = 0; + + strrev(buffer, b2); + return ret; +} + +////////////////////////////////////////////////////////////////////////////// +size_t uitohex(char* buffer, uint32_t data, uint8_t chars) +{ + char *b2 = buffer; + size_t ret = 0; + + if(chars == 0xff || !chars) + { + if(!data) { + *b2++ = '0'; + *b2 = '\0'; + return 1; + } + + while(data) { + uint8_t curval = data & 0x0f; + *b2++ = tochr(curval, 1); + data >>= 4; + } + ret = b2 - buffer; + + } + else + { + ret = chars; + for(uint8_t pos = 0; pos < (uint8_t)ret; ++pos) { + *b2++ = tochr(data & 0x0f, 1); + data >>= 4; + } + + } + *b2-- = 0; + strrev(buffer, b2); + return ret; +} + + +////////////////////////////////////////////////////////////////////////////// +size_t itodec(char* buffer, int data) +{ + if(data < 0) { + *buffer++ = '-'; + return uitodec(buffer, -data) + 1; + } + + return uitodec(buffer, data); +} + +////////////////////////////////////////////////////////////////////////////// +size_t itohex(char* buffer, int data) +{ + if(data < 0) { + *buffer++ = '-'; + return uitohex(buffer, -data, 0) + 1; + } + return uitohex(buffer, data, 0); +} diff --git a/components/f4ll_c/strutil.h b/components/f4ll_c/strutil.h new file mode 100644 index 0000000..49ddc39 --- /dev/null +++ b/components/f4ll_c/strutil.h @@ -0,0 +1,31 @@ +/* + * strutil.h + * + * Created on: Feb 11, 2017 + * Author: compi + */ + +#ifndef _STM32PLUS_STRUTIL_H_ +#define _STM32PLUS_STRUTIL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +size_t strcpy_ex(char *dst, char const *src); +size_t uitodec(char* buffer, uint32_t data); +size_t uitohex(char* buffer, uint32_t data, uint8_t chars); +size_t itodec(char* buffer, int data); +size_t itohex(char* buffer, int data); +void strrev(char *first, char *last); +char tochr(const uint8_t in, const uint8_t upper); + +#ifdef __cplusplus +} +#endif + +#endif /* _STM32PLUS_STRUTIL_H_ */