/*I2S routines*/
/*Usart header file*/
#include "i2s.h"
/*Global Variable definition*/
tI2sData xI2sData;
/*Constant definition*/
eI2sInitError eI2sInit( pI2sInitData data )
{
AT91PS_SSC pSSC = AT91C_BASE_SSC;
/*Disable interrupts*/
AT91F_SSC_DisableIt(pSSC, AT91C_SSC_ENDTX | AT91C_SSC_ENDRX);
/*Enable I2S PIO (SI, SO, SCK)*/
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, (unsigned portLONG) AT91C_PA15_TF | (unsigned portLONG) AT91C_PA16_TK | (unsigned portLONG) AT91C_PA17_TD, 0);
/*Enable I2S Clocks*/
AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_SSC);
/*Reset SSC and disable TX and RX*/
pSSC->SSC_CR = AT91C_SSC_SWRST | AT91C_SSC_RXDIS | AT91C_SSC_TXDIS ;
/*Disable PDC for I2S*/
AT91F_PDC_DisableRx(AT91C_BASE_PDC_SSC);
AT91F_PDC_DisableTx(AT91C_BASE_PDC_SSC);
/*Initialize PDC TX and RX*/
AT91F_PDC_SetTx(AT91C_BASE_PDC_SSC, 0, 0);
AT91F_PDC_SetNextTx(AT91C_BASE_PDC_SSC, 0, 0);
AT91F_PDC_SetRx(AT91C_BASE_PDC_SSC, 0, 0);
AT91F_PDC_SetNextRx(AT91C_BASE_PDC_SSC, 0, 0);
/*Define the Clock Mode Register*/
AT91F_SSC_SetBaudrate(pSSC, configCPU_CLOCK_HZ, (unsigned portLONG) data->config.samplingFreq * ((unsigned portLONG) data->config.bitsBySLot * (unsigned portLONG) data->config.slotByFrame));
/*If enabled, configure the Transmit Frame Mode Register*/
if (data->config.txEnable)
{
pSSC->SSC_TFMR = I2S_ASY_TX_FRAME_SETTING(data->config.bitsBySLot, data->config.slotByFrame);
pSSC->SSC_TCMR = I2S_ASY_MASTER_TX_SETTING(data->config.bitsBySLot, data->config.slotByFrame);
AT91F_SSC_EnableTx(pSSC);
AT91F_PDC_EnableTx(AT91C_BASE_PDC_SSC);
/*Create and initialize TX semaphores*/
if (!xI2sData.config.txEnabled)
{
vSemaphoreCreateBinary(xI2sData.send.mutex.xSemaphore);
vSemaphoreCreateBinary(xI2sData.send.event.xSemaphore);
xI2sData.send.mutex.xBlockTime = INITIAL_OS_BLOCK_TIME_MAX;
}
xI2sData.config.txEnabled = 1;
}
/*If enabled, configure the Receive Frame Mode Register*/
if (data->config.rxEnable)
{
pSSC->SSC_RFMR = I2S_ASY_TX_FRAME_SETTING(data->config.bitsBySLot, data->config.slotByFrame);
pSSC->SSC_RCMR = I2S_ASY_MASTER_TX_SETTING(data->config.bitsBySLot, data->config.slotByFrame);
AT91F_SSC_EnableRx(pSSC);
AT91F_PDC_EnableRx(AT91C_BASE_PDC_SSC);
/*Create and initialize RX semaphores*/
if (!xI2sData.config.rxEnabled)
{
vSemaphoreCreateBinary(xI2sData.receive.mutex.xSemaphore);
vSemaphoreCreateBinary(xI2sData.receive.event.xSemaphore);
xI2sData.receive.mutex.xBlockTime = INITIAL_OS_BLOCK_TIME_MAX;
}
xI2sData.config.rxEnabled = 1;
}
/*Configure and enable interrupts*/
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SSC, AT91C_AIC_PRIOR_LOWEST + 2, AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, ( void (*)(void) ) vI2sISREntry);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SSC);
return i2sInitSuccess;
}
void vI2sClose(void) //TODOÑ el close cerrando lo q abri
{
AT91PS_SSC pSSC = AT91C_BASE_SSC;
/*Disable I2S PIO (SI, SO, SCK)*/
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, (unsigned portLONG) AT91C_PA15_TF | (unsigned portLONG) AT91C_PA16_TK | (unsigned portLONG) AT91C_PA17_TD);
/*Disable PDC for I2S*/
AT91F_PDC_DisableRx(AT91C_BASE_PDC_SSC);
AT91F_PDC_DisableTx(AT91C_BASE_PDC_SSC);
/*Disable I2S Clocks*/
AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_SSC);
/*Disable TX and RX*/
pSSC->SSC_CR = AT91C_SSC_RXDIS | AT91C_SSC_TXDIS ;
AT91F_SSC_DisableTx(pSSC);
AT91F_SSC_DisableRx(pSSC);
/*Disable interrupts*/
AT91F_SSC_DisableIt(AT91C_BASE_SSC, AT91C_SSC_ENDTX | AT91C_SSC_ENDRX);
AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SSC);
/*Release Semaphores*/
vQueueDelete(xI2sData.send.mutex.xSemaphore);
vQueueDelete(xI2sData.send.event.xSemaphore);
vQueueDelete(xI2sData.receive.mutex.xSemaphore);
vQueueDelete(xI2sData.receive.event.xSemaphore);
/*Set Module as uninit*/
xI2sData.config.txEnabled = 0;
xI2sData.config.rxEnabled = 0;
}
unsigned portCHAR cSendFrame(pI2sSendData pData)
{
unsigned portCHAR errCode;
if (!xI2sData.config.txEnabled) {return ERR_DEV_UNINIT;}
if (xSemaphoreTake(xI2sData.send.mutex.xSemaphore, (portTickType) xI2sData.send.mutex.xBlockTime ) != pdTRUE)
{
return ERR_SEM_TIMEOUT;
}
/*Disable PDC while configuring or on the fly*/
#if I2S_SENDRCV_DIS_W_SETTING == 1
AT91F_PDC_DisableTx(AT91C_BASE_PDC_SSC);
#endif
/*Take blocking semaphore*/
xSemaphoreTake(xI2sData.send.event.xSemaphore, 0);
/*Load wait block time*/
xI2sData.send.event.xBlockTime = pData->xBlockTime;
/*Send the current and the next frame*/
if ((AT91C_BASE_SSC->SSC_TNCR == 0) && (AT91C_BASE_SSC->SSC_TCR == 0))
{
AT91F_PDC_SetTx(AT91C_BASE_PDC_SSC, (char *) pData->data, pData->size/2);
AT91F_PDC_SetNextTx(AT91C_BASE_PDC_SSC, (char *) &(pData->data[pData->size/2]), pData->size/2);
}
else if (AT91C_BASE_SSC->SSC_TNCR == 0)
{
AT91F_PDC_SetNextTx(AT91C_BASE_PDC_SSC, (char *) pData->data, pData->size);
}
/*Enable Transmission*/
#if I2S_SENDRCV_DIS_W_SETTING == 1
AT91F_PDC_EnableTx(AT91C_BASE_PDC_SSC);
#endif
/*Enable Interrupt Mask*/
AT91F_SSC_EnableIt(AT91C_BASE_SSC, AT91C_SSC_ENDTX);
/*Block to wait results*/
if (xSemaphoreTake(xI2sData.send.event.xSemaphore, (portTickType) xI2sData.send.event.xBlockTime ) == pdTRUE)
{
errCode = SUCCESS;
}
else { errCode = ERR_TASK_TIMEOUT; }
/*Release mutex*/
xSemaphoreGive(xI2sData.send.mutex.xSemaphore);
return errCode;
}
unsigned portCHAR cReceiveFrame(pI2sReceiveData pData)
{
unsigned portCHAR errCode;
if (!xI2sData.config.rxEnabled) {return ERR_DEV_UNINIT;}
if (xSemaphoreTake(xI2sData.receive.mutex.xSemaphore, (portTickType) xI2sData.receive.mutex.xBlockTime ) != pdTRUE)
{
return ERR_SEM_TIMEOUT;
}
/*Disable PDC while configuring or on the fly*/
#if I2S_SENDRCV_DIS_W_SETTING == 1
AT91F_PDC_DisableRx(AT91C_BASE_PDC_I2S);
#endif
/*Take blocking semaphore*/
xSemaphoreTake(xI2sData.receive.event.xSemaphore, 0);
/*Load wait block time*/
xI2sData.send.event.xBlockTime = pData->xBlockTime;
/*Receive the current and the next frame*/
if (AT91C_BASE_SSC->SSC_RNCR == 0)
{
AT91F_PDC_SetRx(AT91C_BASE_PDC_SSC, (char *) pData->data, pData->size/2);
AT91F_PDC_SetNextRx(AT91C_BASE_PDC_SSC, (char *) pData->data, pData->size/2);
}
else
{
AT91F_PDC_SetNextRx(AT91C_BASE_PDC_SSC, (char *) pData->data, pData->size);
}
/*Enable Reception*/
#if I2S_SENDRCV_DIS_W_SETTING == 1
AT91F_PDC_EnableRx(AT91C_BASE_PDC_I2S);
#endif
/*Enable Interrupt Mask*/
AT91F_SSC_EnableIt(AT91C_BASE_SSC, AT91C_SSC_ENDRX);
/*Block to wait results*/
if (xSemaphoreTake(xI2sData.receive.event.xSemaphore, (portTickType) xI2sData.receive.event.xBlockTime ) == pdTRUE)
{
errCode = SUCCESS;
}
else { errCode = ERR_TASK_TIMEOUT; }
/*Release mutex*/
xSemaphoreGive(xI2sData.receive.mutex.xSemaphore);
return errCode;
}
void vI2sISR(void)
{
unsigned portLONG ulStatus;
portBASE_TYPE xTaskWokenByI2sSend = pdFALSE;
portBASE_TYPE xTaskWokenByI2sReceive = pdFALSE;
AT91PS_SSC pSSC = AT91C_BASE_SSC;
/* Original cause of the interruption */
ulStatus = pSSC->SSC_SR &= pSSC->SSC_IMR;
/*Is a Transmit interrupt*/
if (ulStatus & AT91C_SSC_ENDTX)
{
/*Nothing more to transmit*/
if (pSSC->SSC_TCR == 0)
{AT91F_SSC_DisableIt(pSSC, AT91C_SSC_ENDTX);}
/*Signal semaphore*/
xSemaphoreGiveFromISR(xI2sData.send.event.xSemaphore, &xTaskWokenByI2sSend);
}
/*Is a Receive interrupt*/
if (ulStatus & AT91C_SSC_ENDRX)
{
/*Nothing more to receive*/
if (pSSC->SSC_RCR == 0) {AT91F_SSC_DisableIt(pSSC, AT91C_SSC_ENDRX);}
/*Signal semaphore*/
xSemaphoreGiveFromISR(xI2sData.receive.event.xSemaphore, &xTaskWokenByI2sReceive);
}
/* End the interrupt in the AIC. */
AT91C_BASE_AIC->AIC_EOICR = 0;
/* If a task was woken by either a character being received or a character
being transmitted then we may need to switch to another task. */
portEND_SWITCHING_ISR(xTaskWokenByI2sSend || xTaskWokenByI2sReceive);
}