📄 spi.c
字号:
//////////
// File Name : SPI_cpuOneTxTransfer
// File Description : Transmit tx channel from power by CPU.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_cpuOneTxTransfer( SPI_channel *ch ) {
int TxWriteCnt;
int i;
// Tx buffer ready and Non-zero Tx Data size and Tx-FIFO Ready.
if ( (ch->m_uTxBuf != NULL) && (ch->m_uTxRemainDataSize > 0) && (Inp32(&ch->m_cBase->spi_status) & (1<<0)) ) {
TxWriteCnt = SPI_TX_FIFO_SIZE - ((Inp32(&ch->m_cBase->spi_status)>>6) & (0x7F));
TxWriteCnt = ( ch->m_uTxRemainDataSize < TxWriteCnt ) ? ( ch->m_uTxRemainDataSize ) : (TxWriteCnt);
}
else {
TxWriteCnt = 0;
}
// TX.
if ( ch->m_eBusSize == SPI_BYTE ) {
u8 * ptr = ch->m_uTxBuf;
for(i=TxWriteCnt;i>0;i--) {
Outp8(&ch->m_cBase->spi_tx_data, *ptr++);
}
ch->m_uTxBuf=ptr;
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
u16 * ptr = (u16*)ch->m_uTxBuf;
TxWriteCnt = (TxWriteCnt & ~(0x1)); // 2 byte align.
for(i=TxWriteCnt>>1;i>0;i--) {
Outp16(&ch->m_cBase->spi_tx_data, *ptr++);
}
ch->m_uTxBuf=(u8*)ptr;
}
else if ( ch->m_eBusSize == SPI_WORD ) {
u32 * ptr = (u32*)ch->m_uTxBuf;
TxWriteCnt = (TxWriteCnt & ~(0x3)); // 4 byte align.
for(i=TxWriteCnt>>2;i>0;i--) {
Outp32(&ch->m_cBase->spi_tx_data, *ptr++);
}
ch->m_uTxBuf=(u8*)ptr;
}
ch->m_uTxRemainDataSize = (ch->m_uTxRemainDataSize - TxWriteCnt < 1 ) ? ( 0 ) : ( ch->m_uTxRemainDataSize - TxWriteCnt );
}
//////////
// File Name : SPI_cpuOneRxTransfer
// File Description : Transmit rx channel from power by CPU.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_cpuOneRxTransfer( SPI_channel *ch ) {
int RxReadCnt;
int i;
// Rx Buffer ready and Non-zero Rx data size and Rx-FIFO Read.
// if ( (ch->m_uRxBuf != NULL) && (ch->m_uRxRemainDataSize > 0 ) && (Inp32(&ch->m_cBase->spi_status) & (1<<1)) ) {
if ( (ch->m_uRxBuf != NULL) && (ch->m_uRxRemainDataSize > 0 ) && ((Inp32(&ch->m_cBase->spi_status)>>13) & (0x7f)) ) {
RxReadCnt = (Inp32(&ch->m_cBase->spi_status)>>13) & (0x7f);
RxReadCnt = ( ch->m_uRxRemainDataSize < RxReadCnt ) ? ( ch->m_uRxRemainDataSize ) : (RxReadCnt);
}
else {
RxReadCnt = 0;
}
// Rx.
if ( ch->m_eBusSize == SPI_BYTE ) {
u8 * ptr = ch->m_uRxBuf;
for(i=RxReadCnt;i>0;i--) {
*ptr++ = Inp8(&ch->m_cBase->spi_rx_data);
}
ch->m_uRxBuf=ptr;
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
u16 * ptr = (u16*)ch->m_uRxBuf;
RxReadCnt = (RxReadCnt & ~(0x1)); // 1 byte align.
for(i=RxReadCnt>>1;i>0;i--) {
*ptr++ = Inp16(&ch->m_cBase->spi_rx_data);
}
ch->m_uRxBuf=(u8*)ptr;
}
else if ( ch->m_eBusSize == SPI_WORD ) {
u32 * ptr = (u32*)ch->m_uRxBuf;
RxReadCnt = (RxReadCnt & ~(0x3)); // 4 byte align.
for(i=RxReadCnt>>2;i>0;i--) {
*ptr++ = Inp32(&ch->m_cBase->spi_rx_data);
}
ch->m_uRxBuf=(u8*)ptr;
}
ch->m_uRxRemainDataSize = ( ch->m_uRxRemainDataSize - RxReadCnt < 1 ) ? ( 0 ) : ( ch->m_uRxRemainDataSize - RxReadCnt );
}
//////////
// File Name : SPI_pollingProcess
// File Description : Polling transmission
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_pollingProcess( SPI_channel * ch ) {
if ( ch->m_eClockMode == SPI_MASTER ) {
if ( ch->m_uTxBuf == NULL ) { // master rx only.
Outp32( &ch->m_cBase->packet_count, (1<<16)|(ch->m_uRxRemainDataSize) );
}
}
if ( ch->m_eClockMode == SPI_MASTER ) {
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) & ~(1<<0) ); // Chip selection ON.- active LOW
Outp32( &ch->m_cBase->clk_cfg, Inp32(&ch->m_cBase->clk_cfg) | (1<<8) ); // clock On.
}
if ( ch->m_uRxBuf != 0 ) {
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<1) ); // Rx channel on
}
if ( ch->m_uTxBuf != 0 ) {
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<0) ); // Tx channel on
}
while(ch->m_uTxRemainDataSize != 0 || ch->m_uRxRemainDataSize != 0)
{
// do until SPI FIFO Ready
while( !(Inp32(&ch->m_cBase->spi_status) & (3<<0)));
if( ch->m_uRxRemainDataSize != 0 ) {
SPI_cpuOneRxTransfer( ch );
}
if( ch->m_uTxRemainDataSize != 0 ) {
SPI_cpuOneTxTransfer( ch );
}
}
}
//////////
// File Name : SPI_interruptHandler
// File Description : This function is interrupt handler for transmission and error handling.
// Input : SPI_channel, SPI VIC number.
// Output : NONE.
// Version :
void SPI_interruptHandler( SPI_channel* ch, int interruptNumber ) {
u8 spi_status;
if ( NUM_SPI0 == interruptNumber ) {
// printf( "NUM_SPI0\n" );
}
else {
// printf( "NUM_SPI1\n" );
}
// Error inspection
spi_status = Inp8(&ch->m_cBase->spi_status);
if( spi_status & (0xf<<2) ) {
if(spi_status & SPI_INT_RX_OVERRUN) {
printf("Rx Overrun Error\n");
}
else if(spi_status & SPI_INT_RX_UNDERRUN) {
printf("Rx Underrun Error\n");
}
else if(spi_status & SPI_INT_TX_OVERRUN) {
printf("Tx Overrun Error\n");
}
else if(spi_status & SPI_INT_TX_UNDERRUN) {
// printf("Tx Underrun Error\n");
}
// ch->m_uTxRemainDataSize = 0; // force stop.
// ch->m_uRxRemainDataSize = 0;
}
// Tx under run , Over run, RX under run, Over run clear
Outp8(&ch->m_cBase->pending_clr, Inp8(&ch->m_cBase->pending_clr)|SPI_INT_RX_UNDERRUN|
SPI_INT_TX_OVERRUN|SPI_INT_TX_UNDERRUN|SPI_INT_RX_FIFORDY );
if( ch->m_uRxRemainDataSize != 0 ) {
SPI_cpuOneRxTransfer( ch );
}
if( ch->m_uTxRemainDataSize != 0 ) {
SPI_cpuOneTxTransfer( ch );
}
if ( ch->m_uTxRemainDataSize == 0 && ch->m_uRxRemainDataSize == 0 ) {
// transfer done.
INTC_Disable( interruptNumber );
if ( ch->m_pCallback != NULL ) {
SPI_transactionDone(ch);
ch->m_pCallback(ch);
}
}
else {
// transfer contine.
// INTC_Enable( interruptNumber );
}
}
//////////
// File Name : SPI_interruptChannel0
// File Description : Interrupt Handler for channel 0
// Input : NONE
// Output : NONE.
// Version :
void __irq SPI_interruptChannel0( void ) {
SPI_channel * ch = &SPI_current_channel[0];
SPI_interruptHandler( ch, NUM_SPI0);
INTC_ClearVectAddr();
}
//////////
// File Name : SPI_interruptChannel1
// File Description : Interrupt Handler for channel 1
// Input : NONE
// Output : NONE.
// Version :
void __irq SPI_interruptChannel1( void ) {
SPI_channel * ch = &SPI_current_channel[1];
SPI_interruptHandler( ch, NUM_SPI1);
INTC_ClearVectAddr();
}
//////////
// File Name : SPI_DMADoneHandler
// File Description : DMA Done Interrupt Handler for channel 0
// Input : NONE
// Output : NONE.
// Version :
void SPI_DMADoneHandler( SPI_channel *ch, DMA_CH dmaCh) {
// which DMA channel between CH_A and CH_B
if ( dmaCh & DMA_A ) {
ch->m_uTxRemainDataSize = 0;
putchar('A'); // At the CPU power mode, must remove print message for system resource.
}
if ( dmaCh & DMA_B ) {
ch->m_uRxRemainDataSize = 0;
putchar('B'); // At the CPU power mode, must remove print message for system resource.
}
if ( dmaCh & DMA_C ) {
ch->m_uTxRemainDataSize = 0;
ch->m_uRxRemainDataSize = 0;
putchar('C');
}
// done
if ( ch->m_uTxRemainDataSize == 0 && ch->m_uRxRemainDataSize == 0 ) {
if ( ch->m_pCallback != NULL ) {
SPI_transactionDone(ch);
ch->m_pCallback(ch);
}
// INTC_Disable(ch->m_ucIntNum); // disable interrupt
}
}
//////////
// File Name : SPI_DMADoneChannel0
// File Description : DMA Done Interrupt Handler for channel 0
// Input : NONE
// Output : NONE.
// Version :
void __irq SPI_DMADoneChannel0( void ) {
SPI_channel* ch = &SPI_current_channel[0];
DMA_CH rxtx = DMACH_GetChannelNumber(&ch->m_sDMA);
DMACH_ClearIntPending(&ch->m_sDMA);
putchar( '0' ); // At the CPU power mode, must remove print message for system resource.
SPI_DMADoneHandler( ch, rxtx);
INTC_ClearVectAddr();
}
//////////
// File Name : SPI_DMADoneChannel1
// File Description : DMA Done Interrupt Handler for channel 1
// Input : NONE
// Output : NONE.
// Version :
void __irq SPI_DMADoneChannel1( void ) {
SPI_channel* ch = &SPI_current_channel[1];
DMA_CH rxtx = DMACH_GetChannelNumber(&ch->m_sDMA);
DMACH_ClearIntPending(&ch->m_sDMA);
putchar( '1' ); // At the CPU power mode, must remove print message for system resource.
SPI_DMADoneHandler( ch, rxtx);
INTC_ClearVectAddr();
}
//////////
// File Name : SPI_ErrorCheck
// File Description : Setting error interrupt handler.
// Input : NONE
// Output : NONE.
// Version :
void SPI_ErrorCheck(SPI_channel* ch) {
Outp8(&ch->m_cBase->int_enable, Inp8(&ch->m_cBase->int_enable)|
(SPI_INT_TRAILING|SPI_INT_RX_OVERRUN|SPI_INT_RX_UNDERRUN|SPI_INT_TX_OVERRUN|
SPI_INT_TX_UNDERRUN|SPI_INT_RX_FIFORDY|SPI_INT_TX_FIFORDY) );
INTC_SetVectAddr( ch->m_ucIntNum, ch->m_fISR);
INTC_Enable( ch->m_ucIntNum);
}
//////////
// File Name : SPI_GPIOPortSet
// File Description : This function set GPIO fit on certain channel.
// Input : NONE
// Output : NONE.
// Version :
void SPI_GPIOPortSet(u8 channel)
{
if ( channel == 1 ) {
GPIO_SetFunctionEach( eGPIO_C, eGPIO_4, 0x2 ); // SPI MISO[1] - EINT2[4], GPC4
GPIO_SetFunctionEach( eGPIO_C, eGPIO_5, 0x2 ); // SPI CLK[1] - EINT2[5], GPC5
GPIO_SetFunctionEach( eGPIO_C, eGPIO_6, 0x2 ); // SPI MOSI[1] - EINT2[6], GPC6
GPIO_SetFunctionEach( eGPIO_C, eGPIO_7, 0x2 ); // SPI CSn[1] - EINT2[7], GPC7
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_4, 0 ); // SPI MISO[1] - EINT2[4], GPC4
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_5, 0 ); // SPI CLK[1] - EINT2[5], GPC5
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_6, 0 ); // SPI MOSI[1] - EINT2[6], GPC6
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_7, 0 ); // SPI CSn[1] - EINT2[7], GPC7
}
else { // channel 0
GPIO_SetFunctionEach( eGPIO_C, eGPIO_0, 0x2 ); // SPI MISO[0] - ADDR_CF[0], Eint2[0], GPC0
GPIO_SetFunctionEach( eGPIO_C, eGPIO_1, 0x2 ); // SPI CLK[0] - ADDR_CF[1], EINT2[1], GPC1
GPIO_SetFunctionEach( eGPIO_C, eGPIO_2, 0x2 ); // SPI MOSI[0] - ADDR_CF[2], EINT2[2], GPC2
GPIO_SetFunctionEach( eGPIO_C, eGPIO_3, 0x2 ); // SPI CSn[0] - EINT2[3], GPC3
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_0, 0 ); // SPI MISO[0] - ADDR_CF[0], Eint2[0], GPC0
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_1, 0 ); // SPI CLK[0] - ADDR_CF[1], EINT2[1], GPC1
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_2, 0 ); // SPI MOSI[0] - ADDR_CF[2], EINT2[2], GPC2
GPIO_SetPullUpDownEach( eGPIO_C, eGPIO_3, 0 ); // SPI CSn[0] - EINT2[3], GPC3
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -