void sendAck(SPP_STRUCT* receivedPacket) { SIDLE(); // Debug: halWait(1); DMA_ABORT_CHANNEL(dmaNumberTx); RFTXRXIF = 0; STX(); RFIF &= ~IRQ_DONE; while(RFTXRXIF == 0); RFD = SPP_HEADER_AND_FOOTER_LENGTH + SPP_ACK_LENGTH; RFTXRXIF = 0; while(RFTXRXIF == 0); RFTXRXIF = 0; RFD = receivedPacket->srcAddress; while(RFTXRXIF == 0); RFTXRXIF = 0; RFD = myAddress; while(RFTXRXIF == 0); RFTXRXIF = 0; RFD = ACK; while(!(RFIF & IRQ_DONE)); RFIF &= ~IRQ_DONE; return; }
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- DMA_DESC* culDmaAllocChannel(UINT8* pDmaChannelNumber, FUNCTION* callBackFunction) { DMA_DESC* dmaDesc; BYTE savedIntEnable = 0x00; INT8 i; // Checking for an unassigned DMA channel for(i = 1; i <= DMA_ADM_NUMBER_OF_CHANNELS; i++) { if(dmaTable[i].assigned == FALSE) { break; } } // If no channel is available, the function returns. if(i > DMA_ADM_NUMBER_OF_CHANNELS) { *pDmaChannelNumber = 0x00; dmaDesc = NULL; } // An available table entry was found else { // Deactivating the channel and erasing old interrupt flag DMA_ABORT_CHANNEL(i); DMAIRQ &= ~(1 << i); // Storing interrupt enable register and turning off interrupts. savedIntEnable = IEN0; INT_GLOBAL_ENABLE(INT_OFF); // Reserving the DMA channel. dmaTable[i].assigned = TRUE; dmaTable[i].callBackFunction = callBackFunction; *pDmaChannelNumber = i; // Restoring old interrupt enable register. IEN0 = savedIntEnable; dmaDesc = &dmaChannel1to4[i-1]; } // Returning pointer to the DMA descriptor return dmaDesc; } // ends culDmaAlloc()
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- void sppReceive(SPP_STRUCT* pReceiveData){ sppRxStatus = RX_WAIT; DMA_ABORT_CHANNEL(dmaNumberRx); // Setting the address to where the received data are to be written. // Setting max number of bytes to receive SET_DMA_DEST(dmaRx,pReceiveData); SET_DMA_LENGTH(dmaRx,255); // Arming the DMA channel. The receiver will initate the transfer when a packet is received. DMA_ARM_CHANNEL(dmaNumberRx); // Debug: SIDLE(); RFIF &= ~IRQ_SFD; RFIM |= IRQ_SFD; // Turning on the receiver SRX(); return; }
void dma_main(void){ #else void main(void){ #endif DMA_DESC dmaChannel; char sourceString[56] = "This is a test string used to demonstrate DMA transfer."; //56 bytes char destString[56]; INT8 i; INT8 errors = 0; initDma(); //Clearing the destination memset(destString,0,sizeof(destString)); // Setting up the DMA channel. SET_WORD(dmaChannel.SRCADDRH, dmaChannel.SRCADDRL, &sourceString); // The start address of the data to be transmitted SET_WORD(dmaChannel.DESTADDRH, dmaChannel.DESTADDRL, &destString); // The start address of the destination. SET_WORD(dmaChannel.LENH, dmaChannel.LENL, sizeof(sourceString)); // Setting the number of bytes to transfer. dmaChannel.VLEN = VLEN_USE_LEN; // Using the length field to determine how many bytes to transfer. dmaChannel.PRIORITY = PRI_HIGH; // High priority. dmaChannel.M8 = M8_USE_8_BITS; // Irrelevant since length is determined by the LENH and LENL. dmaChannel.IRQMASK = FALSE; // The DMA shall not issue an IRQ upon completion. dmaChannel.DESTINC = DESTINC_1; // The destination address is to be incremented by 1 after each transfer. dmaChannel.SRCINC = SRCINC_1; // The source address inremented by 1 byte after each transfer. dmaChannel.TRIG = DMATRIG_NONE; // The DMA channel will be started manually. dmaChannel.TMODE = TMODE_BLOCK; // The number of bytes specified by LENH and LENL is transferred. dmaChannel.WORDSIZE = WORDSIZE_BYTE; // One byte is transferred each time. // Using DMA channel 0. // Setting where the DMA channel is to read the desciptor and arming the DMA channel. DMA_SET_ADDR_DESC0(&dmaChannel); DMA_ABORT_CHANNEL(0); DMA_ARM_CHANNEL(0); //Waiting for the user to start the transfer. lcdUpdate((char*)"Press S1",(char*)"to start DMA."); while(!buttonPushed()); // Clearing all DMA complete flags and starting the transfer. DMAIRQ = 0x00; DMA_START_CHANNEL(0); // Waiting for the DMA to finish. while(!(DMAIRQ & DMA_CHANNEL_0)); // Verifying that data is transferred correctly for(i=0;i<sizeof(sourceString);i++) { if(sourceString[i] != destString[i]) errors++; } //Displaying the result if(errors == 0) {lcdUpdate((char*)"Dma transfer",(char*)"correct!");} else {lcdUpdate((char*)"Error in DMA",(char*)"Transfer");} haltApplicationWithLED(); return; }
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- BYTE sppSend(SPP_STRUCT* pPacketPointer){ BYTE res = TRUE; // Checking that length is not too long if (pPacketPointer->payloadLength > SPP_MAX_PAYLOAD_LENGTH) { res = TOO_LONG; sppTxStatus = TX_IDLE; } // Flipping the sequence bit, writing total packet length and address if the transfer is not a retransmission. // If it is a retransmission, the fields are correct if(!(pPacketPointer->flags & RETRANSMISSION)) { pPacketPointer->flags ^= SEQUENCE_BIT; pPacketPointer->payloadLength += SPP_HEADER_AND_FOOTER_LENGTH; pPacketPointer->srcAddress = myAddress; } // Setting up the DMA DMA_ABORT_CHANNEL(dmaNumberTx); SET_DMA_SOURCE(dmaTx,pPacketPointer); // Proceed if the packet length is OK. if (res == TRUE) { // Clearing RF interrupt flags and enabling RF interrupts. RFIF &= ~IRQ_DONE; RFIM &= ~IRQ_SFD; INT_SETFLAG(INUM_RF, INT_CLR); #ifdef CCA_ENABLE if(!CCA) { SRX(); // Turning on Rx and waiting to make the RSSI value become valid. halWait(1); } if(CCA) #endif { // Setting up radio DMA_ABORT_CHANNEL(dmaNumberRx); SIDLE(); RFTXRXIF = 0; INT_GLOBAL_ENABLE(FALSE); DMA_ARM_CHANNEL(dmaNumberTx); STX(); INT_GLOBAL_ENABLE(TRUE); sppTxStatus = TX_IN_PROGRESS; if(pPacketPointer->flags & DO_ACK) { pAckData = pPacketPointer; waitForAck(); } else { pAckData = NULL; } RFIM |= IRQ_DONE; } #ifdef CCA_ENABLE // The "air" is busy else { res = CHANNEL_BUSY; RFIM &= ~IRQ_DONE; // De-flipping the sequence bit. if(!(pPacketPointer->flags & RETRANSMISSION)) { pPacketPointer->flags ^= SEQUENCE_BIT; } } #endif } return res; } // ends sppSend
//----------------------------------------------------------------------------- // See cul.h for a description of this function. //----------------------------------------------------------------------------- BOOL sppInit(UINT32 frequency, BYTE address){ BYTE res = 0; BOOL status = TRUE; sppSetAddress(address); // Clearing the states of the spp. sppTxStatus = TX_IDLE; sppRxStatus = RX_IDLE; retransmissionCounter = 0; ackTimerNumber = 0; pAckData = 0; // Clearing the RF interrupt flags and enable mask and enabling RF interrupts RFIF = 0; RFIM = 0; INT_SETFLAG(INUM_RF,INT_CLR); INT_ENABLE(INUM_RF,INT_ON); // Setting the frequency and initialising the radio res = halRfConfig(FREQUENCY_4_CC1110); if(res == FALSE){ status = FALSE; } // Always in RX unless sending. //debug: MCSM1 = 0x2F; // MCSM1 = 0x3F; SRX(); // Using the timer 4 administrator to generate interrupt to check if a message is unacked... culTimer4AdmInit(); // Initialising the DMA administrator culDmaInit(); // Requesting a DMA channel for transmit data. No callback function is used. Instead the TX_DONE // interrupt is used to determine when a transfer is finished. Configuring the DMA channel for // transmit. The data address and length will be set prior to each specific transmission. dmaTx = culDmaAllocChannel(&dmaNumberTx, 0); if((dmaNumberTx == 0) || (dmaNumberTx > 4)){ status = FALSE; } culDmaToRadio(dmaTx, SPP_MAX_PAYLOAD_LENGTH + SPP_HEADER_AND_FOOTER_LENGTH, 0, FALSE); // Requesting a DMA channel for receiving data. Giving the address of the callback function. // Configuring the DMA channel for receive. The data address will be set prior to each specific // reception. dmaRx = culDmaAllocChannel(&dmaNumberRx, &rxCallBack); if((dmaNumberRx == 0) || (dmaNumberRx > 4)){ status = FALSE; } culDmaFromRadio(dmaRx, 0, TRUE); // Making sure that none of the channels are armed. DMA_ABORT_CHANNEL(dmaNumberRx); DMA_ABORT_CHANNEL(dmaNumberTx); INT_ENABLE(INUM_DMA, INT_ON); return status; } // ends sppInit
/****************************************************************************** * @fn writeFlashUsingDMA * * @brief * Writes data to flash using DMA. Erases the page in advance if told to. * * Parameters: * * @param BYTE* pSrcAddr * The start of the data to be written to flash. * * INT16 length * The number of bytes to be written to flash. * * WORD flashAddress * The address in flash the data is to be written to. * * BOOL erase * Indicating whether the flash is to be erased or not. * * @return void * ******************************************************************************/ void writeFlashUsingDMA(BYTE* pSrcAddr, INT16 length, WORD flashAddress, BOOL erase) { BYTE buffer[10]; INT_GLOBAL_ENABLE(INT_OFF); // Setting up the flash address, // erasing the page if required. SET_WORD(FADDRH, FADDRL, (int)(flashAddress >> 1)); if(erase == TRUE) { halFlashErasePage(buffer, PAGE_NUMBER); } halWait(0xFF); // Making sure a multiplum of 4 bytes is transferred. while(length & 0x0003){ length++; } SET_WORD(dmaChannel.SRCADDRH, dmaChannel.SRCADDRL, pSrcAddr); // The start address of the segment SET_WORD(dmaChannel.DESTADDRH, dmaChannel.DESTADDRL, &X_FWDATA); // Input of the AES module SET_WORD(dmaChannel.LENH, dmaChannel.LENL, length); // Setting the length of the transfer (bytes) dmaChannel.VLEN = VLEN_USE_LEN; // Using the length field dmaChannel.PRIORITY = PRI_LOW; // High priority dmaChannel.M8 = M8_USE_8_BITS; // Transferring all 8 bits in each byte. dmaChannel.IRQMASK = FALSE; // The DMA complete interrupt flag is set at completion. dmaChannel.DESTINC = DESTINC_0; // The destination address is constant dmaChannel.SRCINC = SRCINC_1; // The address for data fetch is inremented by 1 byte dmaChannel.TRIG = DMATRIG_FLASH; // Setting the FLASH module to generate the DMA trigger dmaChannel.TMODE = TMODE_SINGLE; // A single byte is transferred each time. dmaChannel.WORDSIZE = WORDSIZE_BYTE; // Set to count bytes. // Setting up the DMA. // Clearing all DMA complete flags and arming the channel. DMA_SET_ADDR_DESC0(&dmaChannel); DMA_ABORT_CHANNEL(0); DMAIRQ &= ~DMA_CHANNEL_0; DMA_ARM_CHANNEL(0); asm("NOP"); // Starting to write FLASH_CONFIG(WRITE); // Waiting for the DMA to finish. while(!(DMAIRQ & DMA_CHANNEL_0)); DMAIRQ &= ~DMA_CHANNEL_0; return; }