/* * interrupt.c * * Created on: Aug 29, 2019 * Author: abody */ #include #include #include "dma_helper.h" #include "diag.h" #include "crc_handler.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 InitCrcStatus(CRCSTATUS *st, DMA_TypeDef *dma, uint32_t stream) { InitDmaInfo(&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 = 0xff; memset((void*)st->crcTasks, 0, sizeof(st->crcTasks)); } uint8_t EnqueueCrcTask(CRCSTATUS *status, uint8_t slot, uint8_t *address, uint16_t len, void (*callback)(void*, uint32_t, uint8_t), void* callbackParam) { uint32_t prim = __get_PRIMASK(); uint16_t need_start; while(status->activeSlot == slot); __disable_irq(); need_start = (status->activeSlot == 0xff); status->crcTasks[slot].address = need_start ? NULL : address; status->crcTasks[slot].wordCount = (len+3)/4; status->crcTasks[slot].callback = callback; status->crcTasks[slot].callbackParam = callbackParam; if(need_start) status->activeSlot = slot; __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 WaitCrcResults(CRCSTATUS *status, uint8_t slot) { while(IsSlotQueued(status, slot)); while(GetActiveSlot(status) == slot); } uint32_t ComputeCrc(CRCSTATUS *status, uint8_t slot, uint8_t *address, uint16_t len) { uint32_t result; EnqueueCrcTask(status, slot, address, len, NULL, &result); while(status->crcTasks[slot].callbackParam); return result; } void StartNextCrcTask(CRCSTATUS *status) { uint16_t slot; for(slot = 0; slot < CRCTASKCOUNT; ++slot) if(status->crcTasks[slot].address) { status->activeSlot = slot; CRC->CR = 1; LL_DMA_SetM2MSrcAddress(status->dmaInfo.dma, status->dmaInfo.stream, (uint32_t)status->crcTasks[slot].address); LL_DMA_SetDataLength(status->dmaInfo.dma, status->dmaInfo.stream, status->crcTasks[slot].wordCount); DIAG_CRC_CALC_START(); LL_DMA_EnableStream(status->dmaInfo.dma, status->dmaInfo.stream); status->crcTasks[slot].address = NULL; // marking as started return; } status->activeSlot = 0xff; } void HandleCrcDmaIrq(CRCSTATUS *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 != 0xff) { struct crctask_t *tsk = (struct crctask_t *)&status->crcTasks[status->activeSlot]; 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 != 0xff) { struct crctask_t *tsk = (struct crctask_t *)&status->crcTasks[status->activeSlot]; 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(); }