[Tinyos-beta-commits] CVS: tinyos-1.x/beta/platform/pxa27x I2S.h, NONE, 1.1 I2S.nc, NONE, 1.1 PXA27XI2SC.nc, NONE, 1.1 PXA27XI2SM.nc, NONE, 1.1
Robbie Adler
radler at users.sourceforge.net
Sat Nov 22 16:29:54 PST 2008
Update of /cvsroot/tinyos/tinyos-1.x/beta/platform/pxa27x
In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv7947
Added Files:
I2S.h I2S.nc PXA27XI2SC.nc PXA27XI2SM.nc
Log Message:
initial driver for I2S controller
--- NEW FILE: I2S.h ---
#ifndef __I2S_H__
#define __I2S_H__
typedef enum
{
I2S_1Sample = 0,
I2S_2Samples,
I2S_3Samples,
I2S_4Samples,
I2S_5Samples,
I2S_6Samples,
I2S_7Samples,
I2S_8Samples,
I2S_9Samples,
I2S_10Samples,
I2S_11Samples,
I2S_12Samples,
I2S_13Samples,
I2S_14Samples,
I2S_15Samples,
I2S_16Samples
}I2SFifoLevel_t;
typedef enum
{
I2S_SYSCLK_12p235M = 0xC,
I2S_SYSCLK_11p346M = 0xD,
I2S_SYSCLK_5p622M = 0x1A,
I2S_SYSCLK_4p105M = 0x24,
I2S_SYSCLK_2p811M = 0x34,
I2S_SYSCLK_2p053M = 0x48
}I2SAudioDivider_t;
#endif
--- NEW FILE: I2S.nc ---
/**
*@author Robbie Adler
**/
includes I2S; //this will need to change to #include SSP in the future
interface I2S{
/****************************************
*I2S Configuration routines
****************************************/
/**
*init the port
*
*
*
**/
command result_t initI2S();
event void initI2SDone();
/**
*enable the port
*
*@param enable: port is enabled if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t enableI2S(bool enable);
/**
*enable the port
*
*@param enable: port is enabled for playback if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t enablePlayback(bool enable);
/**
*enable the port
*
*@param enable: port is enabled for recording if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t enableRecord(bool enable);
/**
*inform the port of the direciton of the I2S_BITCLK signal.
*
*@param enable: signal is input if TRUE, output if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t setBitClkDir(bool input);
/**
*enable MSB-justified mode
*
*@param enable: MSB-justified mode is used if TRUE, normal I2S mode is used of FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t enableMSBJustifiedMode(bool enable);
/**
*configure the depth of the RX FIFO at which point an interrupt is generated
*
*@param level: fifo level...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t setRxFifoLevel(I2SFifoLevel_t level);
/**
*configure the depth of the TX FIFO at which point an interrupt is generated
*
*@param level: fifo level...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t setTxFifoLevel(I2SFifoLevel_t level);
/**
*configure the audio clock divider for the I2S hardware
*
*@param level: clk divider...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t setAudioClkDivider(I2SAudioDivider_t divider);
}
--- NEW FILE: PXA27XI2SC.nc ---
//@author Robbie Adler
configuration PXA27XI2SC{
provides{
interface BulkTxRx;
interface I2S;
}
}
implementation{
components PXA27XI2SM as I2SM,
PXA27XDMAC,
PXA27XInterruptM;
BulkTxRx=I2SM.BulkTxRx;
I2S=I2SM.I2S;
I2SM.I2SInterrupt -> PXA27XInterruptM.PXA27XIrq[IID_I2S];
I2SM.RxDMAChannel -> PXA27XDMAC.PXA27XDMAChannel[unique("DMAChannel")];
I2SM.TxDMAChannel -> PXA27XDMAC.PXA27XDMAChannel[unique("DMAChannel")];
}
--- NEW FILE: PXA27XI2SM.nc ---
/**
* @author Robbie Adler
**/
includes mmu;
module PXA27XI2SM{
provides{
interface BulkTxRx;
interface I2S;
}
uses{
interface PXA27XDMAChannel as RxDMAChannel;
interface PXA27XDMAChannel as TxDMAChannel;
interface PXA27XInterrupt as I2SInterrupt;
}
}
implementation {
#include "paramtask.h"
#ifndef I2S_DEFAULTDMARXPRIORITY
#define I2S_DEFAULTDMARXPRIORITY (DMA_Priority2|DMA_Priority3|DMA_Priority4)
#endif
#ifndef I2S_DEFAULTDMATXPRIORITY
#define I2S_DEFAULTDMATXPRIORITY (DMA_Priority2|DMA_Priority3|DMA_Priority4)
#endif
bool gInitDone=FALSE;
bool gEnablePlayback = FALSE;
bool gEnableRecord = FALSE;
bool gBitClkInput = FALSE;
bool gEnableMSBJustifiedMode = FALSE;
I2SFifoLevel_t gRxFIFOLevel = I2S_8Samples;
I2SFifoLevel_t gTxFIFOLevel = I2S_8Samples;
I2SAudioDivider_t gAudioClkDivider = I2S_SYSCLK_2p053M;
norace uint32_t *gRxBuffer;
norace uint16_t gRxNumBytes, gRxBufferPos;
//norace hack!!!
norace uint32_t *gTxBuffer;
norace uint16_t gTxNumBytes, gTxBufferPos;
task void signalInitDone(){
signal I2S.initI2SDone();
}
command result_t I2S.initI2S(){
//unconditionally reconfigure the GPIO functionality just in case things get overwritten in between calls to init
//this would cover the case where the port was use for a little while, unconfigured and used for something else, and then
//reconfigured and used again
if(gBitClkInput == TRUE){
GPIO_SET_ALT_FUNC(I2S_BITCLK,I2S_BITCLK_IN_ALTFN, GPIO_IN);
}
else{
GPIO_SET_ALT_FUNC(I2S_BITCLK,I2S_BITCLK_OUT_ALTFN, GPIO_OUT);
}
GPIO_SET_ALT_FUNC(I2S_SYSCLK,I2S_SYSCLK_ALTFN, GPIO_OUT);
GPIO_SET_ALT_FUNC(I2S_SYNC,I2S_SYNC_ALTFN, GPIO_OUT);
GPIO_SET_ALT_FUNC(I2S_DATA_IN,I2S_DATA_IN_ALTFN, GPIO_IN);
GPIO_SET_ALT_FUNC(I2S_DATA_OUT,I2S_DATA_OUT_ALTFN, GPIO_OUT);
if(gInitDone == FALSE){
return call RxDMAChannel.requestChannel(DMAID_I2S_RX,I2S_DEFAULTDMARXPRIORITY, TRUE);
}
else{
post signalInitDone();
}
return SUCCESS;
}
/****************************************
*I2S Configuration routines
****************************************/
/**
*enable the port
*
*@param enable: port is enabled if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t I2S.enableI2S(bool enable){
if(gInitDone == FALSE){
return FAIL;
}
/**
*
* I2S_SYSCLK = K4 (113)
* I2S_SYNC = J4 (31)
* I2S_BITCLK = K1 (28)
* I2S_DATA_IN = K2 (29)
* I2S_DATA_OUT = G6 (30)
*
*
*
* From section 14.4.1 of the PXA27X developer's manual, the step to init are:
* 1.) set I2S_BITCLK direction
* 2.) choose between I2S or MSB-justified modes. WM8940 uses normal I2S mode
* 3.) optionally use programmed I/O to prime the tx fifo
* 4.) Set the SACRO to enable (set ENB bit) and to set tx and rx fifo thresholds
*
*
**/
if(enable == TRUE){
CKEN |= (CKEN_CKEN8);
//SADIV = SADIV_SADIV(gAudioClkDivider);
SACR0 = SACR0_RST;
SACR0 &= ~SACR0_RST;
SACR1 = ((gEnableMSBJustifiedMode == TRUE)?SACR1_AMSL:0) | ((gEnableRecord == FALSE)?SACR1_DREC:0) | ((gEnablePlayback == FALSE)?SACR1_DRPL:0);
SADIV = SADIV_SADIV(gAudioClkDivider);
SACR0 = SACR0 = SACR0_RFTH(gRxFIFOLevel) | SACR0_TFTH(gTxFIFOLevel) | ((gBitClkInput == FALSE)?SACR0_BCKD:0) | SACR0_ENB;
// SADIV = SADIV_SADIV(gAudioClkDivider);
}
else{
CKEN &= ~CKEN_CKEN8;
SACR0 = SACR0_RST;
}
return SUCCESS;
}
/**
*enable the port
*
*@param enable: port is enabled for playback if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t I2S.enablePlayback(bool enable){
gEnablePlayback = enable;
return SUCCESS;
}
/**
*enable the port
*
*@param enable: port is enabled for recording if TRUE, disabled if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t I2S.enableRecord(bool enable){
gEnableRecord = enable;
return SUCCESS;
}
/**
*inform the port of the direciton of the I2S_BITCLK signal.
*
*@param enable: signal is input if TRUE, output if FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t I2S.setBitClkDir(bool input){
gBitClkInput = input;
return SUCCESS;
}
/**
*enable MSB-justified mode
*
*@param enable: MSB-justified mode is used if TRUE, normal I2S mode is used of FALSE
*
*@return FAIL if error, SUCCESS otherwise
**/
command result_t I2S.enableMSBJustifiedMode(bool enable){
gEnableMSBJustifiedMode = enable;
return SUCCESS;
}
/**
*configure the depth of the RX FIFO at which point an interrupt is generated
*
*@param level: fifo level...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t I2S.setRxFifoLevel(I2SFifoLevel_t level){
gRxFIFOLevel = level;
return SUCCESS;
}
/**
*configure the depth of the TX FIFO at which point an interrupt is generated
*
*@param level: fifo level...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t I2S.setTxFifoLevel(I2SFifoLevel_t level){
gTxFIFOLevel = level;
return SUCCESS;
}
/**
*configure the audio clock divider for the I2S hardware
*
*@param level: clk divider...see I2S.h for encodings
*
*@return FAIL if error, SUCCESS otherwise
*/
command result_t I2S.setAudioClkDivider(I2SAudioDivider_t divider){
gAudioClkDivider = divider;
return SUCCESS;
}
void configureRxDMA(uint8_t *RxBuffer, uint16_t NumBytes, bool bEnableTargetAddrIncrement){
call RxDMAChannel.setSourceAddr(0x40400080);
call RxDMAChannel.setTargetAddr((uint32_t)RxBuffer);
call RxDMAChannel.enableSourceAddrIncrement(FALSE);
call RxDMAChannel.enableTargetAddrIncrement(TRUE);
call RxDMAChannel.enableSourceFlowControl(TRUE);
call RxDMAChannel.enableTargetFlowControl(FALSE);
call RxDMAChannel.setTransferLength(NumBytes);
call RxDMAChannel.setMaxBurstSize(DMA_32ByteBurst);
call RxDMAChannel.setTransferWidth(DMA_4ByteWidth);
}
command result_t BulkTxRx.BulkReceive(uint8_t *RxBuffer, uint16_t NumBytes){
return FAIL;
}
void configureTxDMA(uint8_t *TxBuffer, uint16_t NumBytes){
call TxDMAChannel.setSourceAddr((uint32_t)TxBuffer);
call TxDMAChannel.setTargetAddr(0x40400080);
call TxDMAChannel.enableSourceAddrIncrement(TRUE);
call TxDMAChannel.enableTargetAddrIncrement(FALSE);
call TxDMAChannel.enableSourceFlowControl(FALSE);
call TxDMAChannel.enableTargetFlowControl(TRUE);
call TxDMAChannel.setTransferLength(NumBytes);
call TxDMAChannel.setMaxBurstSize(DMA_32ByteBurst);
call TxDMAChannel.setTransferWidth(DMA_4ByteWidth);
}
command result_t BulkTxRx.BulkTransmit(uint8_t *TxBuffer, uint16_t NumBytes){
//port has now been opened
atomic{
gTxBuffer = (uint32_t *)TxBuffer;
gTxNumBytes = NumBytes;
}
//flush the data back to memory
configureTxDMA(TxBuffer,NumBytes);
call TxDMAChannel.run(DMA_ENDINTEN);
return SUCCESS;
}
command result_t BulkTxRx.BulkTxRx(BulkTxRxBuffer_t *TxRxBuffer, uint16_t NumBytes){
return FAIL;
}
event result_t RxDMAChannel.requestChannelDone(){
call TxDMAChannel.requestChannel(DMAID_I2S_TX,I2S_DEFAULTDMATXPRIORITY, TRUE);
return SUCCESS;
}
async event void RxDMAChannel.endInterrupt(uint16_t numBytesSent){
//it is the handler's responsibility to call invalidateDCache((uint8_t *)gRxBuffer, gRxNumBytes);
gRxBuffer = (uint32_t *)signal BulkTxRx.BulkReceiveDone((uint8_t *)gRxBuffer,
gRxNumBytes);
if(gRxBuffer){
//we want to do another read of gRxNumBytes)
//we should still have our DMA channel, so just all set size and run!
call RxDMAChannel.preconfiguredRun((uint32_t)gRxBuffer, gRxNumBytes, FALSE);
}
}
async event void RxDMAChannel.eorInterrupt(uint16_t numBytesSent){
}
async event void RxDMAChannel.stopInterrupt(uint16_t numBytesSent){
}
async event void RxDMAChannel.startInterrupt(){
}
event result_t TxDMAChannel.requestChannelDone(){
gInitDone = TRUE;
post signalInitDone();
return SUCCESS;
}
async event void TxDMAChannel.endInterrupt(uint16_t numBytesSent){
gTxBuffer = (uint32_t *)signal BulkTxRx.BulkTransmitDone((uint8_t *)gTxBuffer,
gTxNumBytes);
if(gTxBuffer){
//we want to do another read of gRxNumBytes)
#if 0
configureTxDMA(gTxBuffer,gTxNumBytes);
call TxDMAChannel.run(DMA_ENDINTEN);
#else
call TxDMAChannel.preconfiguredRun((uint32_t)gTxBuffer, gTxNumBytes, TRUE);
#endif
}
}
async event void TxDMAChannel.eorInterrupt(uint16_t numBytesSent){
}
async event void TxDMAChannel.stopInterrupt(uint16_t numBytesSent){
}
async event void TxDMAChannel.startInterrupt(){
}
async event void I2SInterrupt.fired(){
return;
}
default async event uint8_t *BulkTxRx.BulkReceiveDone(uint8_t *RxBuffer,
uint16_t NumBytes){return NULL;}
default async event uint8_t *BulkTxRx.BulkTransmitDone(uint8_t *TxBuffer,
uint16_t NumBytes){return NULL;}
default async event BulkTxRxBuffer_t *BulkTxRx.BulkTxRxDone(BulkTxRxBuffer_t *TxRxBuffer,
uint16_t NumBytes){return NULL;}
}
More information about the Tinyos-beta-commits
mailing list