/* * interrupt.c * * Created on: Aug 29, 2019 * Author: abody */ #include #include #if defined(HAVE_DIAG) #include "diag.h" #endif #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 #ifndef MOCKABLE #define MOCKABLE(x) x #endif void Crc_StartNextTask(struct crcstatus_t *status); void MOCKABLE(Crc_InitStatus)(struct crcstatus_t *st, CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream) { st->crcUnit = crcUnit; 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)&crcUnit->DR); st->activeSlot = NULL; st->firstSlot = NULL; } void MOCKABLE(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->firstSlot; status->firstSlot = slot; __set_PRIMASK(prim); } uint8_t MOCKABLE(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 MOCKABLE(Crc_IsSlotQueued)(struct crcslotlistitem_t *slot, uint8_t task) { return ((struct crcslottask_t volatile)slot->tasks[task]).address != NULL; } uint8_t MOCKABLE(Crc_IsSlotBusy)(struct crcslotlistitem_t *slot, uint8_t task) { struct crcslottask_t volatile *taskPtr = &slot->tasks[task]; return taskPtr->callback != NULL || taskPtr->callbackParam != NULL; } void MOCKABLE(Crc_WaitResults)(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task) { while(Crc_IsSlotBusy(slot, task)); } uint8_t MOCKABLE(Crc_Enqueue)(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, void *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(Crc_IsSlotBusy(slot, 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) { DIAG_CRC_CALC_START(); status->crcUnit->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; } uint32_t MOCKABLE(Crc_Compute)(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, void *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 void MOCKABLE(Crc_StartNextTask)(struct crcstatus_t *status) { char moreTasks; uint8_t index = 0; do { struct crcslotlistitem_t *slot = status->firstSlot; moreTasks = 0; while(slot) { if(index < slot->count) { if(slot->tasks[index].address) { DIAG_CRC_CALC_START(); status->activeSlot = slot; status->activeTask = index; status->crcUnit->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; } // !!!PORTABILITY WARNING!!! using registers and bits directly. should be reviewed extremely when porting to a different MCU void MOCKABLE(Crc_HandleDmaIrq)(struct crcstatus_t *status) { uint8_t success = 1; DIAG_INTERRUPT_IN(); if((*status->dmaInfo.isReg & status->dmaInfo.tcMask) || (*status->dmaInfo.isReg & status->dmaInfo.teMask)) { if(*status->dmaInfo.isReg & status->dmaInfo.teMask) success = 0; *status->dmaInfo.ifcReg = *status->dmaInfo.isReg & (status->dmaInfo.tcMask | 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, status->crcUnit->DR, success); else if(tsk->callbackParam) *(uint32_t*)tsk->callbackParam = success ? status->crcUnit->DR : 0xffffffff; tsk->callback = tsk->callbackParam = NULL; // marking as inactive DIAG_CRC_CALC_END(); Crc_StartNextTask(status); } } DIAG_INTERRUPT_OUT(); }