📄 spi.c
字号:
//////////
// File Name : SPI_interruptTransaction
// File Description : Execute Interrupt Mode .
// Input : SPI_channel
// Output : success or fail.
// Version :
bool SPI_interruptTransaction( 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 ) {
if ( ch->m_bIsAutoChipSelection == FALSE ) {
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) & ~(0x3<<0) ); // Chip selection ON.- active LOW
}
// 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.
}
Outp32( &ch->m_cBase->int_enable,
( (ch->m_uTxRemainDataSize!=0) ? (SPI_INT_TX_FIFORDY) : (0) ) |// Tx Buffer Ready
( (ch->m_uRxRemainDataSize!=0) ? (SPI_INT_TRAILING|SPI_INT_RX_FIFORDY|SPI_INT_RX_OVERRUN|SPI_INT_RX_UNDERRUN) : (0) ) );// Rx buffer Ready.
Outp32( &ch->m_cBase->pending_clr, 0xffffffff ); // interrupt pending clear.
ch->m_ucIntNum = (ch->m_ucChannelNum==0)?(NUM_SPI0):(NUM_SPI1);
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
}
INTC_SetVectAddr( ch->m_ucIntNum, ch->m_fISR);
INTC_Enable( ch->m_ucIntNum);
if ( ch->m_pCallback == NULL ) {
// Until Transfer Done.
while( ch->m_uTxRemainDataSize != 0 );
while( ch->m_uRxRemainDataSize != 0 );
SPI_transactionDone(ch);
}
return TRUE;
}
//////////
// File Name : SPI_dmaTransaction
// File Description : Execute DMA Mode .
// Input : SPI_channel
// Output : success or fail.
// Version :
bool SPI_dmaTransaction( 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 ) {
if ( ch->m_bIsAutoChipSelection == FALSE ) {
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) & ~(0x3<<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->mode_cfg, Inp32(&ch->m_cBase->mode_cfg) | (1<<2) ); // DMA mode Rx On.
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<1) ); // Rx channel on
SPI_RxDMAInit(ch, 0, (u32)ch->m_uRxBuf, ch->m_uRxRemainDataSize ); // SPI_RX_DATA
Outp32( &ch->m_cBase->pending_clr, 0xffffffff);
DMACH_Start(&ch->m_sDMA);
}
if ( ch->m_uTxBuf != 0 ) {
Outp32( &ch->m_cBase->mode_cfg, Inp32(&ch->m_cBase->mode_cfg) | (1<<1) ); // DMA mode Tx On.
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<0) ); // Tx channel on
SPI_TxDMAInit(ch, (u32)ch->m_uTxBuf, 0, ch->m_uTxRemainDataSize ); // SPI_TX_DATA
Outp32( &ch->m_cBase->pending_clr, 0xffffffff);
DMACH_Start(&ch->m_sDMA);
}
// Blocking Context, when callback-function pointer is NULL
if ( ch->m_pCallback == NULL ) {
// Until Transfer Done.
while( ch->m_uTxRemainDataSize != 0 );
while( ch->m_uRxRemainDataSize != 0 );
DMACH_Stop(&ch->m_sDMA); // Stop DMA
INTC_Disable(ch->m_ucIntNum); // Disable DMA Interrupt
SPI_transactionDone(ch);
}
return TRUE;
}
//////////
// File Name : SPI_dmaTransaction
// File Description : Execute Polling Mode .
// Input : SPI_channel
// Output : success or fail.
// Version :
bool SPI_pollingTransaction(SPI_channel * ch ) {
// SPI_ErrorCheck(ch);
// SPI_pollingProcess(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 ) {
if ( ch->m_bIsAutoChipSelection == FALSE ) {
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) & ~(0x3<<0) ); // Chip selection ON.- active LOW
}
// 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 );
}
}
SPI_transactionDone(ch);
if ( ch->m_pCallback != NULL )
ch->m_pCallback(ch);
return TRUE;
}
// youngbo.song
// This function use for periperal DMA Test.
// have to remove, Test Only.
int SPI_PtoPTransaction( SPI_channel * ch, SPI_transfer_mode mode, u32 size, void (*callbackFn)(SPI_channel *ch) ) {
DATA_SIZE dataSize;
ch->m_pCallback = callbackFn;
ch->m_eTransferMode = mode;
// Do data size alignment
if ( ch->m_eBusSize == SPI_WORD ) {
size = (size+3) & ~(0x3); // word align
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
size = (size+1) & ~(0x1); // half word align
}
// renew setting.
SPI_setBasicRegister( ch );
// Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)&~(3<<0) ); // Tx/Rx channel Off
// Outp32(&ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (1<<0) ); // Chip selection OFF - active LOW.
// Outp32(&ch->m_cBase->clk_cfg, Inp32(&ch->m_cBase->clk_cfg) & ~(1<<8) ); // clock Off.
// Auto Chip Selection.
if ( ch->m_bIsAutoChipSelection == TRUE ) {
Outp32( &ch->m_cBase->slave_sel, (Inp32(&ch->m_cBase->slave_sel) & ~(0x3F<<4))|(0x0<<4) );
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (0x1<<1) );
}
Outp32( &ch->m_cBase->mode_cfg, Inp32(&ch->m_cBase->mode_cfg) | (1<<2) ); // DMA mode Rx On.
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<1) ); // Rx channel on
Outp32( &ch->m_cBase->mode_cfg, Inp32(&ch->m_cBase->mode_cfg) | (1<<1) ); // DMA mode Tx On.
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)|(1<<0) ); // Tx channel on
DMAC_InitCh((DMA_UNIT)ch->m_ucDMACon, DMA_C, &ch->m_sDMA); // to do.. another..
#ifdef SPI_NORMAL_DMA
ch->m_ucIntNum = (ch->m_cChannelNum==0)?(NUM_DMA0):(NUM_DMA1);
#else
ch->m_ucIntNum = (ch->m_cChannelNum==0)?(NUM_SDMA0):(NUM_SDMA1);
#endif
INTC_SetVectAddr(ch->m_ucIntNum, ch->m_fDMA);
INTC_Enable(ch->m_ucIntNum);
// Interrupt Clear
DMACH_ClearIntPending(&ch->m_sDMA);
DMACH_ClearErrIntPending(&ch->m_sDMA);
if ( ch->m_eBusSize == SPI_WORD ) {
size=(size+3)>>2;
dataSize = WORD;
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
size=(size+1)>>1;
dataSize = HWORD;
}
else {
dataSize = BYTE;
}
DMACH_Setup(DMA_C, 0x0,
(ch->m_ucChannelNum==0)?(0x7F00B01C):(0x7F00C01C), TRUE, // RX Fifo.
(ch->m_ucChannelNum==0)?(0x7F00B018):(0x7F00C018), TRUE, // Tx Fifo
dataSize, size, HANDSHAKE,
(ch->m_ucChannelNum==0)?(DMA0_SPI0_RX):(DMA1_SPI1_RX),
(ch->m_ucChannelNum==0)?(DMA0_SPI0_TX):(DMA1_SPI1_TX),
(BURST_MODE)ch->m_eDMAType, &ch->m_sDMA);
Outp32( &ch->m_cBase->pending_clr, 0xffffffff);
DMACH_Start(&ch->m_sDMA);
return TRUE;
}
//////////
// File Name : SPI_transaction
// File Description : Transmit Rx/Tx Data
// Input : SPI_channel, selection DMA/Interrupt/polling mode, Tx buffer, Rx buffer, Transfer Size
// If user want to execte non blocking mode, than set this callback function.
// when transmission complete, call callback function by interrupt handler.
// Output : transmission size.
// Version :
int SPI_transaction( SPI_channel * ch, SPI_transfer_mode mode, u8* tx_data, u8* rx_data, u32 size, void (*callbackFn)(SPI_channel *ch) ) {
ch->m_pCallback = callbackFn;
ch->m_eTransferMode = mode;
// Do data size alignment
if ( ch->m_eBusSize == SPI_WORD ) {
size = (size+3) & ~(0x3); // word align
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
size = (size+1) & ~(0x1); // half word align
}
// Channel Initialization
if( tx_data != 0 ) {
ch->m_uTxRemainDataSize = size; // Tx Transfer Size.
ch->m_uTxBuf = tx_data; // Tx buffer pointer
}
else {
ch->m_uTxRemainDataSize = 0;
ch->m_uTxBuf = NULL;
}
if( rx_data != 0 ) {
ch->m_uRxRemainDataSize = size; // Rx Transfer Size.
ch->m_uRxBuf = rx_data; // Rx buffer pointer
}
else {
ch->m_uRxRemainDataSize = 0;
ch->m_uRxBuf = NULL;
}
// renew setting.
SPI_setBasicRegister( ch );
// Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)&~(3<<0) ); // Tx/Rx channel Off
// Outp32(&ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (1<<0) ); // Chip selection OFF - active LOW.
// Outp32(&ch->m_cBase->clk_cfg, Inp32(&ch->m_cBase->clk_cfg) & ~(1<<8) ); // clock Off.
// Auto Chip Selection.
if ( ch->m_bIsAutoChipSelection == TRUE ) {
Outp32( &ch->m_cBase->slave_sel, (Inp32(&ch->m_cBase->slave_sel) & ~(0x3F<<4))|(0x0<<4) );
Outp32( &ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (0x1<<1) );
}
if (mode == SPI_POLLING_MODE ) {
SPI_pollingTransaction( ch );
}
else if ( mode == SPI_INTERRUPT_MODE ) {
SPI_interruptTransaction( ch );
}
else if (mode == SPI_DMA_MODE ) {
SPI_dmaTransaction( ch );
}
return size;
}
//////////
// File Name : SPI_transactionDone
// File Description : This funtion invoked by transmission routine automatically.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_transactionDone( SPI_channel * ch ) {
if ( ch->m_eClockMode == SPI_MASTER && ch->m_uTxBuf != NULL ) {
// while ( Inp32(&ch->m_cBase->spi_status) & ( 0x7F << 6) ); // wait Tx FIFO empty.
while ( !(Inp32(&ch->m_cBase->spi_status) & ( 1<<21 ) ) ); // wait Tx done signal.
}
// // Tx condition only.
if ( ch->m_eClockMode == SPI_MASTER ) {
if ( ch->m_bIsAutoChipSelection == FALSE ) {
Outp32(&ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (1<<0) ); // Chip selection OFF - active LOW.
Outp32(&ch->m_cBase->clk_cfg, Inp32(&ch->m_cBase->clk_cfg) & ~(1<<8) ); // clock Off.
}
}
// Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg)&~(3<<0) ); // Tx/Rx channel Off
}
//////////
// File Name : SPI_close
// File Description : spi_channel close.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_close( SPI_channel * ch ) {
memset( ch, 0, sizeof (SPI_channel) );
}
//////////
// File Name : SPI_printStatus
// File Description : Print status register for debugging.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_printStatus( SPI_channel * ch ) {
printf ( "Tx_done : %d\n", ( Inp32(&ch->m_cBase->spi_status) & (1<<21) )>>21 );
printf ( "Trailing byte : %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<20) )>>20 );
printf ( "RxFIFOlevel : %d\n", ( Inp32(&ch->m_cBase->spi_status) & (0x7F<<13) )>>13 );
printf ( "TxFIFOlevel : %d\n", ( Inp32(&ch->m_cBase->spi_status) & (0x7F<<6) )>>6 );
printf ( "RxOver-run err: %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<5) )>>5 );
printf ( "RxUnder-run err: %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<4) )>>4 );
printf ( "TxOver-run err : %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<3) )>>3 );
printf ( "TxUnder-run err: %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<2) )>>2 );
printf ( "Rx FIFO Rdy : %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<1) )>>1 );
printf ( "Tx FIFO Rdy : %d\n" , ( Inp32(&ch->m_cBase->spi_status) & (1<<0) ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -