📄 spi.c
字号:
/**************************************************************************************
*
* Project Name : S3C6400 Validation
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6400.
* Anybody can use this software without our permission.
*
*--------------------------------------------------------------------------------------
*
* File Name : hs_spi.c
*
* File Description : This file implements the API functon for High Speed SPI.
*
* Author : Youngbo, Song
* Dept. : AP Development Team
* Created Date : 2007/01/29
* Version : 0.1
*
* History
* - Created(Youngbo,Song 2007/01/29)
*
**************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6400.h"
#include "system.h"
#include "intc.h"
#include "gpio.h"
#include "sysc.h"
#include "spi.h"
SPI_channel SPI_current_channel[2];
//////////
// File Name : SPI_reset
// File Description : This function reset certain spi channel.
// Input : SPI_channel
// Output : NONE.
// Version :
void SPI_reset( SPI_channel * ch ) {
// reset with clock delay..
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg) & ~(0x3F) ); // clean register
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg) | (1<<5) );
Delay(10);
// release reset signal.
Outp32( &ch->m_cBase->ch_cfg, Inp32(&ch->m_cBase->ch_cfg) & ~(1<<5) );
}
//////////
// File Name : SPI_channel_Init
// File Description : This function reset certain spi channel.
// Input : SPI_channel
// Output : NONE.
// Version :
SPI_channel* SPI_channel_Init( int channel ) {
SPI_channel* ch = &SPI_current_channel[channel];
memset ( (void*)ch, 0, sizeof(SPI_channel) );
ch->m_ucChannelNum = channel;
if ( channel == 0 ) {
ch->m_cBase = (SPI_SFR*)SPI0_BASE;
ch->m_ucIntNum = NUM_SPI0;
ch->m_fDMA= SPI_DMADoneChannel0;
ch->m_fISR = SPI_interruptChannel0;
#ifdef SPI_NORMAL_DMA
ch->m_ucDMACon = DMA0;
SYSC_SelectDMA( eSEL_SPI0_TX, 1 ); // normal DMA setting.
SYSC_SelectDMA( eSEL_SPI0_RX, 1 ); // normal DMA setting.
#else
ch->m_ucDMACon = SDMA0;
SYSC_SelectDMA( eSEL_SPI0_TX, 0 ); // secure DMA setting.
SYSC_SelectDMA( eSEL_SPI0_RX, 0 ); // secure DMA setting.
#endif
}
else if ( channel == 1 ) {
ch->m_cBase = (SPI_SFR*)SPI1_BASE;
ch->m_ucIntNum = NUM_SPI1;
ch->m_fDMA = SPI_DMADoneChannel1;
ch->m_fISR = SPI_interruptChannel1;
#ifdef SPI_NORMAL_DMA
ch->m_ucDMACon = DMA1;
SYSC_SelectDMA( eSEL_SPI1_TX, 1 ); // normal DMA setting.
SYSC_SelectDMA( eSEL_SPI1_RX, 1 ); // normal DMA setting.
#else
ch->m_ucDMACon = SDMA1;
SYSC_SelectDMA( eSEL_SPI1_TX, 0 ); // secure DMA setting.
SYSC_SelectDMA( eSEL_SPI1_RX, 0 ); // secure DMA setting.
#endif
}
else {
Assert(0);
}
Outp32(&ch->m_cBase->slave_sel, Inp32(&ch->m_cBase->slave_sel) | (1<<0) ); // Chip selection OFF - active LOW.
SPI_GPIOPortSet(channel); // channel GPIO setting.
return ch;
}
//////////
// File Name : SPI_open
// File Description : This function create certain spi channel.
// Input : channel number, SPI_clock_mode, CPOL, CPHA, SPI_clock_selection, clock frequency, channel size, bus size, DMA Type
// Output : SPI_channel
// Version :
SPI_channel * SPI_open( u8 channel, SPI_clock_mode master, SPI_CPOL cpol, SPI_CPHA cpha, SPI_clock_selection clock,
u32 clk_freq, SPI_transfer_data_type ch_size, SPI_transfer_data_type bus_size, SPI_DMA_type dma_type )
{
u8 ucPrescaler;
SPI_channel* ch = SPI_channel_Init(channel);
SPI_reset( ch );
// channel.
ch->m_cChannelNum = channel;
// 1. SPI Channel setting.
ch->m_eClockMode = master;
ch->m_eCPOL = cpol;
ch->m_eCPHA = cpha;
// 2. Clock Config
// to do make clock source.
if ( clock == SPI_USB_CLK ) {
ucPrescaler = (u8)(((float)48000000)/(float)2/(float)clk_freq - (float)1);
}
else if ( clock == SPI_EPLL_CLK ) {
ucPrescaler = (u8)(((float)100000000)/(float)2/(float)clk_freq - (float)1);
}
else { //( clock == SPI_PCLK )
ucPrescaler = (u8)(((float)g_PCLK)/(float)2/(float)clk_freq - (float)1);
}
ch->m_eClockSource = clock;
ch->m_cPrescaler = ucPrescaler;
// 3. Mode Config
ch->m_eChSize = ch_size;
ch->m_uTraillingCnt = (u16)0x3ff; // default Trailling count setting
ch->m_eBusSize = bus_size;
ch->m_ucRxLevel = (u8)0x20; // default setting.
ch->m_ucTxLevel = (u8)0x20; // default setting.
ch->m_eDMAType = dma_type;
// default swap mode setting.
SPI_setSwapMode( ch, SPI_NO_SWAP, SPI_NO_SWAP);
// default feed back clock setting.
SPI_setFeedbackClock( ch, SPI_6NS_DELAY );
ch->m_bIsAutoChipSelection = FALSE;
return ch;
}
//////////
// File Name : SPI_setSwapMode
// File Description : This function initializes rx/tx swap mode.
// Input : SPI_channel, SPI_feedbackClock
// Output : NONE
// Version :
void SPI_setSwapMode( SPI_channel * ch, SPI_swapMode rx_swap, SPI_swapMode tx_swap ) {
// rx swap mode setting.
if ( rx_swap == SPI_NO_SWAP ) {
ch->m_eRxSwap = SPI_NO_SWAP;
}
else if(rx_swap == SPI_EN_SWAP ) { // default case.
ch->m_eRxSwap = SPI_BYTE_SWAP;
}
else {
ch->m_eRxSwap = rx_swap;
}
// tx swap mode setting.
if ( tx_swap == SPI_NO_SWAP ) {
ch->m_eTxSwap = SPI_NO_SWAP;
}
else if(tx_swap == SPI_EN_SWAP ) { // default case.
ch->m_eTxSwap = SPI_BYTE_SWAP;
}
else {
ch->m_eTxSwap = tx_swap;
}
// swap mode SFR setting.
Outp8( &ch->m_cBase->swap_config, (ch->m_eRxSwap << 4) | ch->m_eTxSwap );
}
//////////
// File Name : SPI_setFeedbackClock
// File Description : This function initializes a feedback clock.
// Input : SPI_channel, SPI_feedbackClock
// Output : NONE
// Version :
void SPI_setFeedbackClock( SPI_channel* ch, SPI_feedbackClock clock ) {
ch->m_eFeedbackClock = clock;
Outp8( &ch->m_cBase->feedback_clk, clock );
}
//////////
// File Name : SPI_setTxRxTriggerLevel
// File Description : This function initialize FIFO trigger levels.
// Input : SPI_channel, rx trigger level, tx trigger level
// Output : NONE
// Version :
void SPI_setTxRxTriggerLevel( SPI_channel * ch, u8 rxLevel, u8 txLevel ) {
ch->m_ucRxLevel = rxLevel; // rx trigger level
ch->m_ucTxLevel = txLevel; // tx trigger level
}
//////////
// File Name : SPI_setBasicRegister
// File Description : This function initializes a certain spi ch.
// Input : SPI_channel
// Output : NONE
// Version :
void SPI_setBasicRegister( SPI_channel* ch ) {
Outp32( &ch->m_cBase->ch_cfg,// (Inp32(&ch->m_cBase->ch_cfg)&~(0x7<<2))| // Clean Register
(ch->m_eClockMode<<4)| // Master/Slave
(ch->m_eCPOL<<3)| // CPOL - active high/row
(ch->m_eCPHA<<2) ); // CPHA - transfer format.
Outp32( &ch->m_cBase->clk_cfg, (Inp32(&ch->m_cBase->clk_cfg) & ~(0x7ff))| // clean register.
(ch->m_eClockSource<<9) | // Clock setting.
( ( (ch->m_eClockMode==SPI_MASTER)?(1):(0) )<<8) | // clock enable
ch->m_cPrescaler); // prescaler setting.
Outp32( &ch->m_cBase->mode_cfg, (Inp32(&ch->m_cBase->mode_cfg)&(u32)(1<<31)) | // clean register.
(ch->m_eChSize<<29)| // channel transfer size.
(ch->m_uTraillingCnt<<19)| // trailling count.
(ch->m_eBusSize<<17)| // bus transfer size.
(ch->m_ucRxLevel<<11)| // Rx trigger level
(ch->m_ucTxLevel<<5)| // Tx trigger level
(ch->m_eDMAType<<0) ); // DMA type
}
//////////
// File Name : SPI_TxDMAInit
// File Description : Initialze DMA Channel for TX.
// Input : SPI_channel , Source Address, Destination Address, Transfer byte Size.
// Output : NONE.
// Version :
void SPI_TxDMAInit ( SPI_channel * ch, u32 uSrcAddr, u32 uDstAddr, u32 uDataCnt) {
DATA_SIZE dataSize;
DMAC_InitCh((DMA_UNIT)ch->m_ucDMACon, DMA_A, &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 ) {
uDataCnt=(uDataCnt+3)>>2;
dataSize = WORD;
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
uDataCnt=(uDataCnt+1)>>1;
dataSize = HWORD;
}
else {
dataSize = BYTE;
}
DMACH_Setup(DMA_A, 0x0,
uSrcAddr, FALSE,
(ch->m_ucChannelNum==0)?(0x7F00B018):(0x7F00C018), TRUE,
dataSize, uDataCnt, HANDSHAKE,
MEM,(ch->m_ucChannelNum==0)?(DMA0_SPI0_TX):(DMA1_SPI1_TX),
(BURST_MODE)ch->m_eDMAType, &ch->m_sDMA);
}
//////////
// File Name : SPI_RxDMAInit
// File Description : Initialze DMA Channel for Rx.
// Input : SPI_channel , Source Address, Destination Address, Transfer byte Size.
// Output : NONE.
// Version :
void SPI_RxDMAInit(SPI_channel* ch, u32 uSrcAddr, u32 uDstAddr, u32 uDataCnt) {
DATA_SIZE dataSize;
DMAC_InitCh((DMA_UNIT)ch->m_ucDMACon, DMA_B, &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 ) {
uDataCnt=(uDataCnt+3)>>2;
dataSize = WORD;
}
else if ( ch->m_eBusSize == SPI_HWORD ) {
uDataCnt=(uDataCnt+1)>>1;
dataSize = HWORD;
}
else {
dataSize = BYTE;
}
DMACH_Setup(DMA_B, 0x0,
(ch->m_ucChannelNum==0)?(0x7F00B01C):(0x7F00C01C), TRUE,
uDstAddr, FALSE,
dataSize, uDataCnt, HANDSHAKE,
(ch->m_ucChannelNum==0)?(DMA0_SPI0_RX):(DMA1_SPI1_RX), MEM,
(BURST_MODE)ch->m_eDMAType, &ch->m_sDMA);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -