//------------------------------------------------------------------------------ /// Initializes the Spid structure and the corresponding SPI hardware. /// Always returns 0. /// \param pSpid Pointer to a Spid instance. /// \param pSpiHw Associated SPI peripheral. /// \param spiId SPI peripheral identifier. //------------------------------------------------------------------------------ unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId) { // Initialize the SPI structure pSpid->pSpiHw = pSpiHw; pSpid->spiId = spiId; pSpid->semaphore = 1; pSpid->pCurrentCommand = 0; // Enable the SPI clock WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId)); // Execute a software reset of the SPI twice WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); // Configure SPI in Master Mode with No CS selected !!! WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS); // Disable the PDC transfer WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); // Enable the SPI WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN); // Enable the SPI clock WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId)); return 0; }
//------------------------------------------------------------------------------ //./ Initializes the Spid structure and the corresponding SPI & DMA hardware. //./ The driver will uses DMA channel 0 for RX and DMA channel 1 for TX. //./ The DMA channels are freed automatically when no SPI command processing. //./ \param pSpid Pointer to a Spid instance. //./ \param pSpiHw Associated SPI peripheral. //./ \param spiId SPI peripheral identifier. //./ \return Always 0. //------------------------------------------------------------------------------ //unsigned char SPI_D_Configure(SpiD *pSpiD, AT91S_SPI *pSpiHw, unsigned char spiId) unsigned char SPI_D_Configure(SpiD *pSpiD, AT91S_SPI *pSpiHw, unsigned char spiId) { // Initialize the SPI structure pSpiD->pSpiHw = pSpiHw; pSpiD->spiId = spiId; pSpiD->semaphore = 1; pSpiD->pCurrentCommand = 0; // Enable the SPI Peripheral PERIPH_ENABLE(pSpiD->spiId); // Execute a software reset of the SPI twice WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST); // Configure SPI in Master Mode with No CS selected !!! WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS); // Disable the PDC transfer #if !defined(at91sam3u) WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); #endif // Disable the SPI TX & RX WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS); // Disable the SPI Peripheral PERIPH_DISABLE(pSpiD->spiId); return 0; }
//------------------------------------------------------------------------------ /// The SPI_Handler must be called by the SPI Interrupt Service Routine with the /// corresponding Spi instance. /// The SPI_Handler will unlock the Spi semaphore and invoke the upper application /// callback. /// \param pSpid Pointer to a Spid instance. //------------------------------------------------------------------------------ void SPID_Handler(Spid *pSpid) { SpidCmd *pSpidCmd = pSpid->pCurrentCommand; AT91S_SPI *pSpiHw = pSpid->pSpiHw; volatile unsigned int spiSr; // Read the status register spiSr = READ_SPI(pSpiHw, SPI_SR); if (spiSr & AT91C_SPI_RXBUFF) { // Disable transmitter and receiver WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); // Disable the SPI clock WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId)); // Disable buffer complete interrupt WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF); // Release the dataflash semaphore pSpid->semaphore++; // Invoke the callback associated with the current command if (pSpidCmd && pSpidCmd->callback) pSpidCmd->callback(0, pSpidCmd->pArgument); // Nothing must be done after. A new DF operation may have been started // in the callback function. } }
//------------------------------------------------------------------------------ /// SPI DMA transfer ISR, Handle RX complete //------------------------------------------------------------------------------ void SPI_D_Handler(SpiD *pSpiD) { unsigned int dmaStatus; SpiDCmd *pSpiDCmd = pSpiD->pCurrentCommand; AT91S_SPI *pSpiHw = pSpiD->pSpiHw; dmaStatus = DMA_GetStatus(); if ((dmaStatus & AT91C_CBTC) == 0) return; if ((dmaStatus & (DMA_CBTC << DMA_CHANNEL_0)) == 0) return; // Disable the SPI TX & RX WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS); // Disable the SPI Peripheral PERIPH_DISABLE(pSpiD->spiId); // Disable DMA DMA_Disable(); // Disable DMA Peripheral PERIPH_DISABLE(AT91C_ID_HDMA); // Release the dataflash semaphore pSpiD->semaphore++; // Invoke the callback associated with the current command if (pSpiDCmd && pSpiDCmd->callback) { pSpiDCmd->callback(0, pSpiDCmd->pArgument); } }
//------------------------------------------------------------------------------ //./ Starts a SPI master transfer. This is a non blocking function. It will //./ return as soon as the transfer is started. //./ Returns 0 if the transfer has been started successfully; otherwise returns //./ SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not //./ valid. //./ \param pSpid Pointer to a Spid instance. //./ \param pCommand Pointer to the SPI command to execute. //------------------------------------------------------------------------------ unsigned char SPI_D_SendCommand(SpiD *pSpiD, SpiDCmd *pCommand) { AT91S_SPI *pSpiHw = pSpiD->pSpiHw; unsigned int spiMr; // Try to get the dataflash semaphore if (pSpiD->semaphore == 0) { return SPI_D_ERROR_LOCK; } pSpiD->semaphore--; // Enable the SPI Peripheral PERIPH_ENABLE(pSpiD->spiId); // Disable PDC transmitter and receiver #if !defined(at91sam3u) WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); #endif // Write to the MR register spiMr = READ_SPI(pSpiHw, SPI_MR); spiMr |= AT91C_SPI_PCS; spiMr &= ~((1 << pCommand->spiCs) << 16); WRITE_SPI(pSpiHw, SPI_MR, spiMr); // Initialize DMA controller using channel 0 for RX, 1 for TX. configureDmaChannels(); configureLinkList(pSpiHw, pCommand); // Initialize the callback pSpiD->pCurrentCommand = pCommand; // Enable the SPI TX & RX WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN); // Start DMA 0(RX) && 1(TX) DMA_EnableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1)); // Enable DMA Interrupts DMA_EnableIt( (DMA_CBTC << DMA_CHANNEL_0) | (DMA_CBTC << DMA_CHANNEL_1)); return 0; }
//------------------------------------------------------------------------------ //./ Configures the parameters for the device corresponding to the cs. //./ \param pSpid Pointer to a Spid instance. //./ \param cs number corresponding to the SPI chip select. //./ \param csr SPI_CSR value to setup. //------------------------------------------------------------------------------ void SPI_D_ConfigureCS(SpiD *pSpiD, unsigned char cs, unsigned int csr) { AT91S_SPI *pSpiHw = pSpiD->pSpiHw; // Enable the SPI Peripheral PERIPH_ENABLE(pSpiD->spiId); // Write CS WRITE_SPI(pSpiHw, SPI_CSR[cs], csr); // Disable the SPI Peripheral PERIPH_DISABLE(pSpiD->spiId); }
//------------------------------------------------------------------------------ /// Configures the parameters for the device corresponding to the cs. /// \param pSpid Pointer to a Spid instance. /// \param cs number corresponding to the SPI chip select. /// \param csr SPI_CSR value to setup. //------------------------------------------------------------------------------ void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr) { AT91S_SPI *pSpiHw = pSpid->pSpiHw; WRITE_SPI(pSpiHw, SPI_CSR[cs], csr); }
//------------------------------------------------------------------------------ /// Starts a SPI master transfer. This is a non blocking function. It will /// return as soon as the transfer is started. /// Returns 0 if the transfer has been started successfully; otherwise returns /// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not /// valid. /// \param pSpid Pointer to a Spid instance. /// \param pCommand Pointer to the SPI command to execute. //------------------------------------------------------------------------------ unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand) { AT91S_SPI *pSpiHw = pSpid->pSpiHw; unsigned int spiMr; // Try to get the dataflash semaphore if (pSpid->semaphore == 0) return SPID_ERROR_LOCK; pSpid->semaphore--; // Enable the SPI clock WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId)); // Disable transmitter and receiver WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS); // Write to the MR register spiMr = READ_SPI(pSpiHw, SPI_MR); spiMr |= AT91C_SPI_PCS; spiMr &= ~((1 << pCommand->spiCs) << 16); WRITE_SPI(pSpiHw, SPI_MR, spiMr); // Initialize the two SPI PDC buffer WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd); WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize); WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd); WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize); WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData); WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize); WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData); WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize); // Initialize the callback pSpid->pCurrentCommand = pCommand; // Enable transmitter and receiver WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN); // Enable buffer complete interrupt WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF); return 0; }
/*************************************************************************** Declaration : void get_audio_packet(void) Description : ***************************************************************************/ void get_audio_packet(void) { int audio_sample; volatile char status; char audio_byte; int i; ENABLE_RF_SPI; read_rf_byte(R_RX_PAYLOAD); signal_in[0] = read_rf_byte(R_RX_PAYLOAD); signal_in[1] = read_rf_byte(R_RX_PAYLOAD); WRITE_SPI(R_RX_PAYLOAD); WAIT_SPI_READY; for(i=0; i< AUDIO_SAMPLES; i++) { // Get audio byte in nRF24L01 FIFO READ_SPI(audio_byte); WRITE_SPI(R_RX_PAYLOAD); // Expand audio to 16-bit audio_sample = expand_audio(audio_byte); *output_write_ptr++ = (char)(audio_sample >> 8); *output_write_ptr++ = (char)(audio_sample); #ifndef USB *output_write_ptr++ = 0; *output_write_ptr++ = 0; #endif if(output_write_ptr >= &output[AUDIO_BUFFER_LENGTH]) output_write_ptr = &output[0]; } if(!(protocol_flags & FLAG_BUFFER_SYNC2)) { output_write_ptr = (char *)((unsigned int)output_read_ptr + 0xFFFC); output_write_ptr -= 40; if(output_write_ptr < &output[0]) output_write_ptr += AUDIO_BUFFER_LENGTH; protocol_flags |= FLAG_BUFFER_SYNC2; } #ifdef HEADSET // Handle slip due to clock differences i = (int)output_read_ptr - (int)output_write_ptr; if(i < 0) i += AUDIO_BUFFER_LENGTH; if(i < 20) { #ifdef USB output_write_ptr -= 2; #else output_write_ptr -= 4; #endif if(output_write_ptr < &output[0]) output_write_ptr = &output[AUDIO_BUFFER_LENGTH-1]; } if(i > 60) { #ifdef USB output_write_ptr -= 2; #else output_write_ptr -= 4; #endif if(output_write_ptr >= &output[AUDIO_BUFFER_LENGTH]) output_write_ptr = &output[0]; } #endif READ_SPI_STATUS(status); READ_SPI(audio_byte); DISABLE_RF_SPI; }
/*************************************************************************** Declaration : void put_audio_packet(void) Description : ***************************************************************************/ void put_audio_packet(void) { int audio_sample,abs_audio; volatile char status; char audio_byte; int i; // Put RF Payload ENABLE_RF_SPI; write_rf_byte(W_TX_PAYLOAD); // Put Signalling bytes write_rf_byte(signal_out[0]); write_rf_byte(signal_out[1]); // Put audio bytes for(i=0; i< AUDIO_SAMPLES; i++) { // Read 16bit audio sample from input buffer audio_sample = (unsigned int)(*input_read_ptr++) << 8; audio_sample += (unsigned int)*input_read_ptr++; #ifndef USB input_read_ptr += 2; #endif if(input_read_ptr >= &input[AUDIO_BUFFER_LENGTH]) input_read_ptr = &input[0]; // Compress 16bit --> 12bit --> 8bit if(audio_sample < 0) abs_audio = -audio_sample; else abs_audio = audio_sample; audio_byte = pgm_read_byte(&Alaw_compress[(abs_audio >> 4) & 0x7FF]); if(audio_sample < 0) audio_byte |= 0x80; // Put audio byte in nRF24L01 FIFO READ_SPI_STATUS(status); WRITE_SPI(audio_byte); } if(!(protocol_flags & FLAG_BUFFER_SYNC1)) { input_read_ptr = (char *)((unsigned int)input_write_ptr & 0xFFFC); input_read_ptr -= 40; if(input_read_ptr < &input[0]) input_read_ptr += AUDIO_BUFFER_LENGTH; protocol_flags |= FLAG_BUFFER_SYNC1; } #ifdef HEADSET // Handle slip due to clock differences i = (int)input_write_ptr - (int)input_read_ptr; if(i < 0) i += AUDIO_BUFFER_LENGTH; if(i < 20) { #ifdef USB input_read_ptr -= 2; #else input_read_ptr -= 4; #endif if(input_read_ptr < &input[0]) input_read_ptr = &input[AUDIO_BUFFER_LENGTH-1]; } if(i > 60) { #ifdef USB input_read_ptr -= 2; #else input_read_ptr -= 4; #endif if(input_read_ptr >= &input[AUDIO_BUFFER_LENGTH]) input_read_ptr = &input[0]; } #endif WAIT_SPI_READY; DISABLE_RF_SPI; }