/* * ll_crc_handler.cpp * * Created on: Oct 26, 2019 * Author: compi */ #include namespace f4ll { crc_handler::crc_handler(DMA_TypeDef *dma, uint32_t stream) : m_dma(dma, stream) { LL_DMA_EnableIT_TC(dma, stream); LL_DMA_EnableIT_TE(dma, stream); LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&CRC->DR); } void crc_handler::attach_slot(slot_base &slot) { for (unsigned int i = 0; i < slot.m_task_count; ++i) { auto &task(slot[i]); task.m_address = nullptr; task.m_word_count = 0; task.m_callback = nullptr; task.m_callback_param = 0; } uint32_t prim = __get_PRIMASK(); __disable_irq(); slot.m_next = m_first_slot; m_first_slot = &slot; __set_PRIMASK(prim); } bool crc_handler::enqueue(slot_base &slot, uint8_t task, void const *address, uint16_t len, icallback *cb, uintptr_t cbParam) { uint32_t prim = __get_PRIMASK(); bool immediate; // TODO: do we need sanity check here? (is slot attached, is task in range, // etc...?) while (is_active(slot, task)) ; __disable_irq(); immediate = m_active_slot == nullptr; slot[task].m_address = (!immediate) ? address : nullptr; slot[task].m_word_count = (len + 3) / 4; slot[task].m_callback = cb; slot[task].m_callback_param = cbParam; if (immediate) { m_active_slot = &slot; m_activeTask = task; } __set_PRIMASK(prim); if (immediate) { CRC->CR = 1; LL_DMA_SetM2MSrcAddress(m_dma.get_dma(), m_dma.get_stream(), (uint32_t)address); LL_DMA_SetDataLength(m_dma.get_dma(), m_dma.get_stream(), (len + 3) / 4); LL_DMA_EnableStream(m_dma.get_dma(), m_dma.get_stream()); } return immediate; } bool crc_handler::is_active(slot_base &slot, uint8_t task) const { return task < slot.m_task_count && slot[task].m_word_count != 0; } bool crc_handler::is_queued(slot_base &slot, uint8_t task) const { return task < slot.m_task_count && slot[task].m_address != nullptr; } bool crc_handler::is_running(slot_base &slot, uint8_t task) const { return task < slot.m_task_count && slot[task].m_word_count && !slot[task].m_address; } void crc_handler::dma_transfer_completed(void) { if (*m_dma.get_is_reg() & m_dma.get_tc_mask()) { // DMA transfer complete *m_dma.get_ifc_reg() = m_dma.get_tc_mask(); LL_DMA_DisableStream(m_dma.get_dma(), m_dma.get_stream()); if (m_active_slot) { if ((*m_active_slot)[m_activeTask].m_callback) { (*m_active_slot)[m_activeTask].m_callback->crc_succeeded( (*m_active_slot)[m_activeTask].m_callback_param, CRC->DR, m_activeTask); } else if ((*m_active_slot)[m_activeTask].m_callback_param) { *reinterpret_cast((*m_active_slot)[m_activeTask].m_callback_param) = CRC->DR; } } } else if (*m_dma.get_is_reg() & m_dma.get_te_mask()) { // DMA transfer error *m_dma.get_ifc_reg() = m_dma.get_te_mask(); LL_DMA_DisableStream(m_dma.get_dma(), m_dma.get_stream()); if (m_active_slot) { if ((*m_active_slot)[m_activeTask].m_callback) { (*m_active_slot)[m_activeTask].m_callback->crc_failed( (*m_active_slot)[m_activeTask].m_callback_param, CRC->DR, m_activeTask); } else if ((*m_active_slot)[m_activeTask].m_callback_param) { *reinterpret_cast((*m_active_slot)[m_activeTask].m_callback_param) = -1; } } } (*m_active_slot)[m_activeTask].m_callback = nullptr; (*m_active_slot)[m_activeTask].m_callback_param = 0; (*m_active_slot)[m_activeTask].m_word_count = 0; start_next_task(); } void crc_handler::start_next_task(void) { bool moreTasks; uint8_t index = 0; do { slot_base volatile *slot = m_first_slot; moreTasks = false; while (slot) { if (index < slot->m_task_count) { if ((*slot)[index].m_address) { m_active_slot = slot; m_activeTask = index; CRC->CR = 1; LL_DMA_SetM2MSrcAddress(m_dma.get_dma(), m_dma.get_stream(), reinterpret_cast((*slot)[index].m_address)); LL_DMA_SetDataLength(m_dma.get_dma(), m_dma.get_stream(), (*slot)[index].m_word_count); LL_DMA_EnableStream(m_dma.get_dma(), m_dma.get_stream()); (*slot)[index].m_address = nullptr; // marking as started return; } if (index + 1 < slot->m_task_count) { moreTasks = true; } } slot = slot->m_next; } ++index; } while (moreTasks); m_active_slot = nullptr; } void crc_handler::wait_results(slot_base &slot, uint8_t task) const { while (is_queued(slot, task)) ; while (is_active(slot, task)) ; } uint32_t crc_handler::compute(slot_base &slot, uint8_t task, void const *address, uint16_t len) { uint32_t result; enqueue(slot, task, address, len, nullptr, reinterpret_cast(&result)); while (is_active(slot, task)) ; return result; } } // namespace f4ll