⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi.c

📁 s3c6400 ADS下官方测试程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/**************************************************************************************
* 
*	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 + -