Код: void SPI_RESET_CS(SPI_DRIVER_INFO drv_info) { AT91PS_PIO pPIO; unsigned int pins;
pPIO = drv_info->pPIO; pins = drv_info->cs_pins;
pPIO->PIO_SODR = pins; // set level = 1 pPIO->PIO_PER = pins; // Set in PIO mode pPIO->PIO_OER = pins; // Configure in Output pPIO->PIO_PPUDR = pins; // pull-up off
//MOSI, MISO, SPCK pins = drv_info->spi_pins; pPIO->PIO_ASR = pins; // A select pPIO->PIO_PDR = pins; // PIO mode disable pPIO->PIO_PPUDR = pins; //disable pull-up }
void SPI_START_TRANSACTION(HANDLE hnd, SPI_DRIVER_INFO drv_info) { DRV_SPI_MODE mode; AT91PS_SPI pSPI;
mode = (DRV_SPI_MODE)hnd->param[2].as_voidptr; drv_info->pPIO->PIO_CODR = mode->cs_pin;
pSPI = drv_info->pSPI; pSPI->SPI_CSR[0] = mode->cs_reg; pSPI->SPI_IER = AT91C_SPI_ENDRX; } ////////////////////////////////////////////////////////////////////////// // // SPI Driver // // Resposible for: // - // - // Notes: // - SPI master mode(SPI_MR->MSTR=1) supported only // - Fixed peripheral select mode (SPI_MR->PS=0) is used to allow use of PDC // - CSs are driven in PIO mode because of the LASTXFER bug when CSAAT=1 and mutiple transfers // - To perform multiple transfers on a single CS, the LOCK bit must be set for // all handles except the last one in the transaction. // - request for R, W and RW operations are supported // - if Write-only operations are used in multiple transfers (locked handles), the length of // single buffer should be less than sizeof(drv_spi_temp) //////////////////////////////////////////////////////////////////////////
#include "spi_drv.h" #include <tmos.h>
__no_init unsigned char drv_spi_temp[254];
void spi_start_dma(HANDLE hnd, AT91PS_PDC pPDC) { unsigned int len;
len = hnd->len;
if(hnd->res_cmd.low & FLAG_WRITE) pPDC->PDC_TPR = hnd->param[1].as_int; else pPDC->PDC_TPR = RAM_START;
if(hnd->res_cmd.low & FLAG_READ) pPDC->PDC_RPR = hnd->param[0].as_int; else { if( len > sizeof(drv_spi_temp)) { len = sizeof(drv_spi_temp); hnd->param[1].as_int += len; } pPDC->PDC_RPR = (unsigned int)drv_spi_temp; }
pPDC->PDC_RCR = len; pPDC->PDC_TCR = len; hnd->len -= len; }
//*---------------------------------------------------------------------------- //* DCR function //*---------------------------------------------------------------------------- __interwork RES_CODE SPI_DCR(SPI_DRIVER_INFO drv_info, unsigned int reason, void * param) {
switch(reason) { case DCR_RESET: #define pSPI ((AT91PS_SPI) param) //Manual asserting for SPI CSs SPI_RESET_CS(drv_info);
//enable periph clock CfgPMC(drv_info->hw_id);
//Reset SPI pSPI->SPI_CR = AT91C_SPI_SWRST; // set invalid mode pSPI->SPI_MR = 0x00000011; pSPI->SPI_CSR[0] = 0xFF00FE03; pSPI->SPI_CR = AT91C_SPI_SPIEN; pSPI->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; EnableISR(drv_info->hw_id); return RES_OK; #undef pSPI
} return RES_FATAL; } //*----------------------------------------------------------------------------
//*---------------------------------------------------------------------------- //* DSR function //*---------------------------------------------------------------------------- __interwork RES_CODE SPI_DSR(HANDLE hnd, SPI_DRIVER_DATA drv_data, SPI_DRIVER_INFO drv_info) { unsigned int locker;
if((locker = drv_data->locker)) { //lock X if(locker != hnd->client.drv_index) return hnd_try_waiting(hnd, (DRIVER_DATA)drv_data);
if( !(hnd->res_cmd.low & FLAG_LOCK) ) drv_data->locker = 0; if( drv_data->pending) { spi_start_dma(hnd, (AT91PS_PDC)&drv_info->pPDC->PDC_RNPR); drv_data->pending2 = hnd; return svc_HND_SET_STATUS(hnd, RES_PENDING); }
} else { if( drv_data->pending) return hnd_try_waiting(hnd, (DRIVER_DATA)drv_data); SPI_START_TRANSACTION(hnd, drv_info); if( hnd->res_cmd .low & FLAG_LOCK) drv_data->locker = hnd->client.drv_index; }
spi_start_dma(hnd, drv_info->pPDC); drv_data->pending = hnd; return svc_HND_SET_STATUS(hnd, RES_PENDING);
}
//*---------------------------------------------------------------------------- //* ISR function //*---------------------------------------------------------------------------- __interwork void SPI_ISR(SPI_DRIVER_INFO drv_info, AT91PS_SPI pSPI) { SPI_DRIVER_DATA drv_data; HANDLE hnd;
drv_data = drv_info->drv_data;
//read SPI_SR hnd = (HANDLE)pSPI->SPI_SR;
//direct call assuming no higer ISRs will use SPI if( (hnd=drv_data->pending2) ) { if(!pSPI->SPI_RNCR) { drv_data->pending2 = NULL; usr_HND_SET_STATUS(drv_data->pending, RES_OK); drv_data->pending = hnd; } return; }
if(pSPI->SPI_RCR) return;
if( (hnd=drv_data->pending) ) { if(hnd->len) { spi_start_dma(hnd, drv_info->pPDC); return; }
pSPI->SPI_IDR = AT91C_SPI_ENDRX | AT91C_SPI_TXEMPTY; if (!drv_data->locker) { if ( !(pSPI->SPI_SR & AT91C_SPI_TXEMPTY) ) { pSPI->SPI_IER = AT91C_SPI_TXEMPTY; return; } SPI_END_TRANSACTION(drv_info, hnd); } drv_data->pending = NULL; usr_HND_SET_STATUS(hnd, RES_OK); }
if (!drv_data->locker) if( (hnd = drv_data->waiting) ) { drv_data->waiting = hnd->next; drv_data->pending = hnd; SPI_START_TRANSACTION(hnd, drv_info); spi_start_dma(hnd, drv_info->pPDC); if( hnd->res_cmd.low & FLAG_LOCK) drv_data->locker = hnd->client.drv_index; usr_HND_SET_STATUS(hnd, RES_PENDING); }
}
|