/****************************************************************************** * @fn HalUARTPollTxTrigDMA * * @brief Ascertain whether a manual trigger is required for the DMA Tx channel. * * @param None * * @return None *****************************************************************************/ static void HalUARTPollTxTrigDMA(void) { if ((UxCSR & CSR_TX_BYTE) == 0) // If no TXBUF to shift register transfer, then TXBUF may be MT. { if ((dmaCfg.txTick == 0) || ((uint8)(ST0 - dmaCfg.txTick) > HAL_UART_TX_TICK_MIN)) { dmaCfg.txTick = 0; if (dmaCfg.txTrig && HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)) { HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX); } dmaCfg.txTrig = 0; } } else { UxCSR = (CSR_MODE | CSR_RE); // Clear the CSR_TX_BYTE flag. dmaCfg.txTick = ST0; if (dmaCfg.txTick == 0) // Reserve zero to signify that the minimum delay has been met. { dmaCfg.txTick = 0xFF; } } }
/************************************************************************************************** * @fn HalUARTWriteSPI * * @brief Transmit data bytes as a SPI packet. * * input parameters * * @param buf - pointer to the memory of the data bytes to send. * @param len - the length of the data bytes to send. * * output parameters * * None. * * @return Zero for any error; otherwise, 'len'. */ static spiLen_t HalUARTWriteSPI(uint8 *buf, spiLen_t len) { // Already in Tx or Rx transaction #ifdef RBA_UART_TO_SPI // The RBA Bridge is not written to handle re-writes so we must // just let it write if (spiTxLen != 0) #else //!RBA_UART_TO_SPI if (spiTxLen != 0 || SPI_RDY_OUT()) #endif { return 0; } if (len > SPI_MAX_DAT_LEN) { len = SPI_MAX_DAT_LEN; } spiTxLen = len; writeActive = 1; #if defined HAL_SPI_MASTER spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt)); /* DMA TX might need padding */ /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_RX ); spiRxIdx = 0; (void)memset(spiRxBuf, (DMA_PAD ^ 0xFF), SPI_MAX_PKT_LEN * sizeof(uint16)); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_TX ); HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_CSn_OUT(); while((!SPI_RDY_IN()) && (!spiRdyIsr) ); HAL_DMA_MAN_TRIGGER(HAL_SPI_CH_TX); #elif !defined HAL_SPI_MASTER #ifdef POWER_SAVING /* Disable POWER SAVING when transmission is initiated */ CLEAR_SLEEP_MODE(); #endif HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt) + 1); /* slave DMA TX might drop the last byte */ HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_RDY_OUT(); #endif return len; }
/************************************************************************************************** * @fn HalUARTWriteSPI * * @brief Transmit data bytes as a SPI packet. * * input parameters * * @param buf - pointer to the memory of the data bytes to send. * @param len - the length of the data bytes to send. * * output parameters * * None. * * @return Zero for any error; otherwise, 'len'. */ static spiLen_t HalUARTWriteSPI(uint8 *buf, spiLen_t len) { if (spiTxLen != 0) { return 0; } if (len > SPI_MAX_DAT_LEN) { len = SPI_MAX_DAT_LEN; } spiTxLen = len; #if defined HAL_SPI_MASTER spiRdyIsr = 0; spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt)); /* DMA TX might need padding */ /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_RX ); spiRxIdx = 0; (void)memset(spiRxBuf, (DMA_PAD ^ 0xFF), SPI_MAX_PKT_LEN * sizeof(uint16)); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); /* Abort any pending DMA operations */ HAL_DMA_ABORT_CH( HAL_SPI_CH_TX ); HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_CSn_OUT(); while((!SPI_RDY_IN()) && (!spiRdyIsr) ); HAL_DMA_MAN_TRIGGER(HAL_SPI_CH_TX); #elif !defined HAL_SPI_MASTER #ifdef POWER_SAVING /* Disable POWER SAVING when transmission is initiated */ CLEAR_SLEEP_MODE(); #endif SPI_CLR_RDY_OUT(); HAL_DMA_ARM_CH(HAL_SPI_CH_RX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); if ( SPI_RDY_IN() ) { SPI_SET_RDY_OUT(); } spiTxPkt[SPI_LEN_IDX] = len; (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len); spiCalcFcs(spiTxPkt); spiTxPkt[SPI_SOF_IDX] = SPI_SOF; halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX); HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt) + 1); /* slave DMA TX might drop the last byte */ HAL_DMA_ARM_CH(HAL_SPI_CH_TX); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); SPI_SET_RDY_OUT(); #endif return len; }
/************************************************************************************************** * @fn DMAExecCrc * * @brief This function assumes CRC has been initialized and sets up and * starts a dma tranfer from a flash page to the CRC HW module. * * @note This function assumes DMA channel 0 is available for use. * * input parameters * * @param page - A valid flash page number. * @param offset - A valid offset into the page. * @param len - A valid number of bytes to calculate crc of. * * @return None. ************************************************************************************************** */ void DMAExecCrc(uint8 page, uint16 offset, uint16 len) { uint8 memctr = MEMCTR; // Save to restore. // Calculate the offset into the containing flash bank as it gets mapped into XDATA. uint16 address = (offset + HAL_FLASH_PAGE_MAP) + ((page % HAL_FLASH_PAGE_PER_BANK) * HAL_FLASH_PAGE_SIZE); // Pointer to DMA config structure halDMADesc_t *dmaCh0_p = &dmaCh0; #if !defined HAL_OAD_BOOT_CODE halIntState_t is; #endif page /= HAL_FLASH_PAGE_PER_BANK; // Calculate the flash bank from the flash page. #if !defined HAL_OAD_BOOT_CODE HAL_ENTER_CRITICAL_SECTION(is); #endif // Calculate and map the containing flash bank into XDATA. MEMCTR = (MEMCTR & 0xF8) | page; // page is actually bank // Start address for CRC calculation in the XDATA mapped flash bank HAL_DMA_SET_SOURCE(dmaCh0_p, address); // Destination for data transfer, RNDH mapped to XDATA HAL_DMA_SET_DEST(dmaCh0_p, 0x70BD); // One whole page (or len) at a time HAL_DMA_SET_LEN(dmaCh0_p, len); // 8-bit, block, no trigger HAL_DMA_SET_WORD_SIZE(dmaCh0_p, HAL_DMA_WORDSIZE_BYTE); HAL_DMA_SET_TRIG_MODE(dmaCh0_p, HAL_DMA_TMODE_BLOCK); HAL_DMA_SET_TRIG_SRC(dmaCh0_p, HAL_DMA_TRIG_NONE); // SRC += 1, DST = constant, no IRQ, all 8 bits, high priority HAL_DMA_SET_SRC_INC(dmaCh0_p, HAL_DMA_SRCINC_1); HAL_DMA_SET_DST_INC(dmaCh0_p, HAL_DMA_DSTINC_0); HAL_DMA_SET_IRQ(dmaCh0_p, HAL_DMA_IRQMASK_DISABLE); HAL_DMA_SET_M8(dmaCh0_p, HAL_DMA_M8_USE_8_BITS); HAL_DMA_SET_PRIORITY(dmaCh0_p, HAL_DMA_PRI_HIGH); // Tell DMA Controller where above configuration can be found HAL_DMA_SET_ADDR_DESC0(&dmaCh0); // Arm the DMA channel (0) HAL_DMA_ARM_CH(0); // 9 cycles wait asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); // Start DMA tranfer HAL_DMA_MAN_TRIGGER(0); // Wait for dma to finish. while(DMAREQ & 0x1); // Restore bank mapping MEMCTR = memctr; #if !defined HAL_OAD_BOOT_CODE HAL_EXIT_CRITICAL_SECTION(is); #endif }
/****************************************************************************** * @fn HalUARTPollDMA * * @brief Poll a USART module implemented by DMA. * * @param none * * @return none *****************************************************************************/ static void HalUARTPollDMA(void) { uint16 cnt = 0; uint8 evt = 0; if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { rxIdx_t tail = findTail(); // If the DMA has transferred in more Rx bytes, reset the Rx idle timer. if (dmaCfg.rxTail != tail) { dmaCfg.rxTail = tail; // Re-sync the shadow on any 1st byte(s) received. if (dmaCfg.rxTick == 0) { dmaCfg.rxShdw = ST0; } dmaCfg.rxTick = HAL_UART_DMA_IDLE; } else if (dmaCfg.rxTick) { // Use the LSB of the sleep timer (ST0 must be read first anyway). uint8 decr = ST0 - dmaCfg.rxShdw; if (dmaCfg.rxTick > decr) { dmaCfg.rxTick -= decr; dmaCfg.rxShdw = ST0; } else { dmaCfg.rxTick = 0; } } cnt = HalUARTRxAvailDMA(); } else { dmaCfg.rxTick = 0; } if (cnt >= HAL_UART_DMA_FULL) { evt = HAL_UART_RX_FULL; } else if (cnt >= HAL_UART_DMA_HIGH) { evt = HAL_UART_RX_ABOUT_FULL; PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow. } else if (cnt && !dmaCfg.rxTick) { evt = HAL_UART_RX_TIMEOUT; } if (dmaCfg.txMT) { dmaCfg.txMT = FALSE; evt |= HAL_UART_TX_EMPTY; } if (dmaCfg.txShdwValid) { uint8 decr = ST0; decr -= dmaCfg.txShdw; if (decr > dmaCfg.txTick) { // No protection for txShdwValid is required // because while the shadow was valid, DMA ISR cannot be triggered // to cause concurrent access to this variable. dmaCfg.txShdwValid = FALSE; } } if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid) { // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR // to know that DBUF can be overwritten halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); halIntState_t intState; // Clear the DMA pending flag dmaCfg.txDMAPending = FALSE; HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; HAL_ENTER_CRITICAL_SECTION(intState); HAL_DMA_ARM_CH(HAL_DMA_CH_TX); do { asm("NOP"); } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)); HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX); HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX); HAL_EXIT_CRITICAL_SECTION(intState); } else { halIntState_t his; HAL_ENTER_CRITICAL_SECTION(his); if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX) && !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX)) { HAL_EXIT_CRITICAL_SECTION(his); HalUARTIsrDMA(); } else { HAL_EXIT_CRITICAL_SECTION(his); } } if (evt && (dmaCfg.uartCB != NULL)) { dmaCfg.uartCB(HAL_UART_DMA-1, evt); } }