/* * interrupt.c * * Created on: Aug 29, 2019 * Author: abody */ #include #include "main.h" #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, 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->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) { 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; } 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; 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; } 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, status->crcUnit->DR, 1); else if(tsk->callbackParam) *(uint32_t*)tsk->callbackParam = status->crcUnit->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, status->crcUnit->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(); }