506 lines
12 KiB
C++
506 lines
12 KiB
C++
#include "bsp_sercom.h"
|
|
|
|
bool sendDataSlaveWIRE( Sercom *sercom, uint8_t data )
|
|
{
|
|
//Send data
|
|
sercom->I2CS.DATA.bit.DATA = data;
|
|
|
|
//Problems on line? nack received?
|
|
if(!sercom->I2CS.INTFLAG.bit.DRDY || sercom->I2CS.STATUS.bit.RXNACK)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
int availableWIRE( Sercom *sercom )
|
|
{
|
|
if(isMasterWIRE(sercom))
|
|
return sercom->I2CM.INTFLAG.bit.SB;
|
|
else
|
|
return sercom->I2CS.INTFLAG.bit.DRDY;
|
|
}
|
|
|
|
void prepareNackBitWIRE( Sercom *sercom )
|
|
{
|
|
if(isMasterWIRE(sercom)) {
|
|
// Send a NACK
|
|
sercom->I2CM.CTRLB.bit.ACKACT = 1;
|
|
} else {
|
|
sercom->I2CS.CTRLB.bit.ACKACT = 1;
|
|
}
|
|
}
|
|
|
|
void prepareAckBitWIRE( Sercom *sercom )
|
|
{
|
|
if(isMasterWIRE(sercom)) {
|
|
// Send an ACK
|
|
sercom->I2CM.CTRLB.bit.ACKACT = 0;
|
|
} else {
|
|
sercom->I2CS.CTRLB.bit.ACKACT = 0;
|
|
}
|
|
}
|
|
|
|
void prepareCommandBitsWire(Sercom *sercom, uint8_t cmd)
|
|
{
|
|
if(isMasterWIRE(sercom)) {
|
|
sercom->I2CM.CTRLB.bit.CMD = cmd;
|
|
|
|
while(sercom->I2CM.SYNCBUSY.bit.SYSOP)
|
|
{
|
|
// Waiting for synchronization
|
|
}
|
|
} else {
|
|
sercom->I2CS.CTRLB.bit.CMD = cmd;
|
|
}
|
|
}
|
|
|
|
uint8_t readDataWIRE( Sercom *sercom )
|
|
{
|
|
if(isMasterWIRE(sercom))
|
|
{
|
|
while( sercom->I2CM.INTFLAG.bit.SB == 0 )
|
|
{
|
|
// Waiting complete receive
|
|
}
|
|
|
|
return sercom->I2CM.DATA.bit.DATA ;
|
|
}
|
|
else
|
|
{
|
|
return sercom->I2CS.DATA.reg ;
|
|
}
|
|
}
|
|
|
|
void initClock( Sercom *sercom )
|
|
{
|
|
uint8_t clockId = 0;
|
|
|
|
if(sercom == SERCOM0)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM0_CORE;
|
|
}
|
|
else if(sercom == SERCOM1)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM1_CORE;
|
|
}
|
|
|
|
#if defined(SERCOM2)
|
|
else if(sercom == SERCOM2)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM2_CORE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SERCOM3)
|
|
else if(sercom == SERCOM3)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM3_CORE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SERCOM4)
|
|
else if(sercom == SERCOM4)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM4_CORE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(SERCOM5)
|
|
else if(sercom == SERCOM5)
|
|
{
|
|
clockId = GCLK_CLKCTRL_ID_SERCOM5_CORE;
|
|
}
|
|
#endif
|
|
|
|
//Setting clock
|
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
|
|
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
|
|
GCLK_CLKCTRL_CLKEN ;
|
|
|
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCLK_CLKCTRL_ID_SERCOMX_SLOW ) |
|
|
GCLK_CLKCTRL_GEN_GCLK1 |
|
|
GCLK_CLKCTRL_CLKEN ;
|
|
|
|
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
|
|
{
|
|
/* Wait for synchronization */
|
|
}
|
|
}
|
|
|
|
|
|
/* =========================
|
|
* ===== Sercom WIRE
|
|
* =========================
|
|
*/
|
|
void resetWIRE(Sercom *sercom)
|
|
{
|
|
//I2CM OR I2CS, no matter SWRST is the same bit.
|
|
|
|
//Setting the Software bit to 1
|
|
sercom->I2CM.CTRLA.bit.SWRST = 1;
|
|
|
|
//Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
|
|
while(sercom->I2CM.CTRLA.bit.SWRST || sercom->I2CM.SYNCBUSY.bit.SWRST);
|
|
}
|
|
|
|
void enableWIRE(Sercom *sercom)
|
|
{
|
|
|
|
// Enable the I²C master mode
|
|
sercom->I2CM.CTRLA.bit.ENABLE = 1 ;
|
|
|
|
while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 )
|
|
{
|
|
// Waiting the enable bit from SYNCBUSY is equal to 0;
|
|
}
|
|
|
|
// Setting bus idle mode
|
|
sercom->I2CM.STATUS.bit.BUSSTATE = 1 ;
|
|
|
|
while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 )
|
|
{
|
|
// Wait the SYSOP bit from SYNCBUSY coming back to 0
|
|
}
|
|
}
|
|
|
|
void initSlaveWIRE( Sercom *sercom, uint8_t ucAddress )
|
|
{
|
|
// Initialize the peripheral clock and interruption
|
|
initClock(sercom) ;
|
|
resetWIRE(sercom) ;
|
|
|
|
// Set slave mode
|
|
sercom->I2CS.CTRLA.bit.MODE = I2C_SLAVE_OPERATION;
|
|
|
|
sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits
|
|
SERCOM_I2CS_ADDR_ADDRMASK( 0x00ul ) ; // 0x00, only match exact address
|
|
|
|
enableInterruptsWIRE( sercom );
|
|
|
|
while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 )
|
|
{
|
|
// Wait the SYSOP bit from SYNCBUSY to come back to 0
|
|
}
|
|
}
|
|
|
|
/* =========================
|
|
* ===== Sercom UART
|
|
* =========================
|
|
*/
|
|
|
|
void resetUART( Sercom * sercom )
|
|
{
|
|
// Start the Software Reset
|
|
sercom->USART.CTRLA.bit.SWRST = 1 ;
|
|
|
|
while ( sercom->USART.CTRLA.bit.SWRST || sercom->USART.SYNCBUSY.bit.SWRST )
|
|
{
|
|
// Wait for both bits Software Reset from CTRLA and SYNCBUSY coming back to 0
|
|
}
|
|
}
|
|
|
|
bool isDataRegisterEmptyUART( Sercom * sercom )
|
|
{
|
|
//DRE : Data Register Empty
|
|
return sercom->USART.INTFLAG.bit.DRE;
|
|
}
|
|
|
|
void initUART( Sercom * sercom, SercomUartSampleRate sampleRate, uint32_t baudrate)
|
|
{
|
|
initClock(sercom);
|
|
resetUART(sercom);
|
|
|
|
//Setting the CTRLA register
|
|
sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(0x01) |
|
|
SERCOM_USART_CTRLA_SAMPR(sampleRate);
|
|
|
|
//Setting the Interrupt register
|
|
sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | //Received complete
|
|
SERCOM_USART_INTENSET_ERROR; //All others errors
|
|
|
|
uint16_t sampleRateValue;
|
|
|
|
if (sampleRate == SAMPLE_RATE_x16) {
|
|
sampleRateValue = 16;
|
|
} else {
|
|
sampleRateValue = 8;
|
|
}
|
|
|
|
// Asynchronous fractional mode (Table 24-2 in datasheet)
|
|
// BAUD = fref / (sampleRateValue * fbaud)
|
|
// (multiply by 8, to calculate fractional piece)
|
|
uint32_t baudTimes8 = (SystemCoreClock * 8) / (sampleRateValue * baudrate);
|
|
|
|
sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8);
|
|
sercom->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8);
|
|
}
|
|
|
|
void disableInterruptsUART(Sercom * sercom)
|
|
{
|
|
sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_RXC | //Received complete
|
|
SERCOM_USART_INTENCLR_ERROR; //All others errors
|
|
}
|
|
|
|
void initFrame( Sercom * sercom , SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
|
|
{
|
|
//Setting the CTRLA register
|
|
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
|
|
dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
|
|
|
|
//Setting the CTRLB register
|
|
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
|
|
nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
|
|
(parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
|
|
}
|
|
|
|
void initPads( Sercom * sercom , SercomUartTXPad txPad, SercomRXPad rxPad)
|
|
{
|
|
//Setting the CTRLA register
|
|
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(txPad) |
|
|
SERCOM_USART_CTRLA_RXPO(rxPad);
|
|
|
|
// Enable Transceiver and Receiver
|
|
sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
|
|
}
|
|
|
|
int writeDataUART( Sercom * sercom ,uint8_t data)
|
|
{
|
|
// Wait for data register to be empty
|
|
while(!isDataRegisterEmptyUART(sercom));
|
|
|
|
//Put data into DATA register
|
|
sercom->USART.DATA.reg = (uint16_t)data;
|
|
return 1;
|
|
}
|
|
|
|
int writeDataUART( Sercom * sercom , char const *buffer){
|
|
while(*buffer != '\0')
|
|
writeDataUART(sercom, *buffer++);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void enableUART( Sercom * sercom )
|
|
{
|
|
while(sercom->USART.SYNCBUSY.bit.ENABLE || sercom->USART.SYNCBUSY.bit.SWRST);
|
|
|
|
//Setting the enable bit to 1
|
|
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
|
|
|
//Wait for then enable bit from SYNCBUSY is equal to 0;
|
|
while(sercom->USART.SYNCBUSY.bit.ENABLE);
|
|
}
|
|
|
|
void disableUART( Sercom *sercom )
|
|
{
|
|
while(sercom->USART.SYNCBUSY.bit.ENABLE || sercom->USART.SYNCBUSY.bit.SWRST);
|
|
|
|
//Setting the enable bit to 0
|
|
sercom->USART.CTRLA.bit.ENABLE = 0;
|
|
|
|
//Wait for then enable bit from SYNCBUSY is equal to 0;
|
|
while(sercom->USART.SYNCBUSY.bit.ENABLE);
|
|
}
|
|
|
|
void setUARTBaud( Sercom *sercom, uint32_t baudrate )
|
|
{
|
|
disableUART(sercom);
|
|
|
|
// Asynchronous fractional mode (Table 24-2 in datasheet)
|
|
// BAUD = fref / (sampleRateValue * fbaud)
|
|
// (multiply by 8, to calculate fractional piece)
|
|
uint32_t baudTimes8 = (SystemCoreClock * 8) / (16 * baudrate);
|
|
|
|
sercom->USART.BAUD.FRAC.FP = (baudTimes8 % 8);
|
|
sercom->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8);
|
|
|
|
enableUART(sercom);
|
|
}
|
|
|
|
/* =========================
|
|
* ===== Sercom SPI
|
|
* =========================
|
|
*/
|
|
|
|
uint8_t calculateBaudrateSynchronous(uint32_t baudrate)
|
|
{
|
|
return SERCOM_FREQ_REF / (2 * baudrate) - 1;
|
|
}
|
|
|
|
void initSPI( Sercom *sercom, SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder)
|
|
{
|
|
resetSPI(sercom);
|
|
initClock(sercom);
|
|
|
|
//Setting the CTRLA register
|
|
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER |
|
|
SERCOM_SPI_CTRLA_DOPO(mosi) |
|
|
SERCOM_SPI_CTRLA_DIPO(miso) |
|
|
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
|
|
|
|
//Setting the CTRLB register
|
|
sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) |
|
|
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
|
|
|
|
|
|
}
|
|
|
|
void initSPISlave( Sercom *sercom, SercomSpiTXPad miso, SercomRXPad mosi, SercomSpiCharSize charSize, SercomDataOrder dataOrder)
|
|
{
|
|
initClock(sercom);
|
|
resetSPI(sercom);
|
|
|
|
//Setting the CTRLA register
|
|
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_SLAVE |
|
|
SERCOM_SPI_CTRLA_DOPO(miso) |
|
|
SERCOM_SPI_CTRLA_DIPO(mosi) |
|
|
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
|
|
|
|
//Setting the CTRLB register
|
|
sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) |
|
|
SERCOM_SPI_CTRLB_RXEN | SERCOM_SPI_CTRLB_PLOADEN; //Active the SPI receiver.
|
|
|
|
|
|
}
|
|
|
|
void initSPIClock( Sercom *sercom, SercomSpiClockMode clockMode, uint32_t baudrate)
|
|
{
|
|
//Extract data from clockMode
|
|
int cpha, cpol;
|
|
|
|
if((clockMode & (0x1ul)) == 0 )
|
|
cpha = 0;
|
|
else
|
|
cpha = 1;
|
|
|
|
if((clockMode & (0x2ul)) == 0)
|
|
cpol = 0;
|
|
else
|
|
cpol = 1;
|
|
|
|
//Setting the CTRLA register
|
|
sercom->SPI.CTRLA.reg |= ( cpha << SERCOM_SPI_CTRLA_CPHA_Pos ) |
|
|
( cpol << SERCOM_SPI_CTRLA_CPOL_Pos );
|
|
|
|
//Synchronous arithmetic
|
|
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(baudrate);
|
|
}
|
|
|
|
void resetSPI( Sercom *sercom )
|
|
{
|
|
//Setting the Software Reset bit to 1
|
|
sercom->SPI.CTRLA.bit.SWRST = 1;
|
|
|
|
//Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
|
|
while(sercom->SPI.CTRLA.bit.SWRST || sercom->SPI.SYNCBUSY.bit.SWRST);
|
|
}
|
|
|
|
void enableSPI( Sercom *sercom )
|
|
{
|
|
//Setting the enable bit to 1
|
|
sercom->SPI.CTRLA.bit.ENABLE = 1;
|
|
|
|
while(sercom->SPI.SYNCBUSY.bit.ENABLE)
|
|
{
|
|
//Waiting then enable bit from SYNCBUSY is equal to 0;
|
|
}
|
|
}
|
|
|
|
void disableSPI( Sercom *sercom )
|
|
{
|
|
while(sercom->SPI.SYNCBUSY.bit.ENABLE)
|
|
{
|
|
//Waiting then enable bit from SYNCBUSY is equal to 0;
|
|
}
|
|
|
|
//Setting the enable bit to 0
|
|
sercom->SPI.CTRLA.bit.ENABLE = 0;
|
|
|
|
while(sercom->SPI.SYNCBUSY.bit.ENABLE);
|
|
}
|
|
|
|
void setDataOrderSPI( Sercom *sercom, SercomDataOrder dataOrder)
|
|
{
|
|
//Register enable-protected
|
|
disableSPI(sercom);
|
|
|
|
sercom->SPI.CTRLA.bit.DORD = dataOrder;
|
|
|
|
enableSPI(sercom);
|
|
}
|
|
|
|
SercomDataOrder getDataOrderSPI( Sercom *sercom )
|
|
{
|
|
return (sercom->SPI.CTRLA.bit.DORD ? LSB_FIRST : MSB_FIRST);
|
|
}
|
|
|
|
void setBaudrateSPI( Sercom *sercom, uint8_t divider)
|
|
{
|
|
//Can't divide by 0
|
|
if(divider == 0)
|
|
return;
|
|
|
|
//Register enable-protected
|
|
disableSPI(sercom);
|
|
|
|
sercom->SPI.BAUD.reg = calculateBaudrateSynchronous( SERCOM_FREQ_REF / divider );
|
|
|
|
enableSPI(sercom);
|
|
}
|
|
|
|
void setClockModeSPI( Sercom *sercom, SercomSpiClockMode clockMode)
|
|
{
|
|
int cpha, cpol;
|
|
if((clockMode & (0x1ul)) == 0)
|
|
cpha = 0;
|
|
else
|
|
cpha = 1;
|
|
|
|
if((clockMode & (0x2ul)) == 0)
|
|
cpol = 0;
|
|
else
|
|
cpol = 1;
|
|
|
|
//Register enable-protected
|
|
disableSPI(sercom);
|
|
|
|
sercom->SPI.CTRLA.bit.CPOL = cpol;
|
|
sercom->SPI.CTRLA.bit.CPHA = cpha;
|
|
|
|
enableSPI(sercom);
|
|
}
|
|
|
|
uint8_t transferDataSPI( Sercom *sercom, uint8_t data)
|
|
{
|
|
sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register
|
|
|
|
while( sercom->SPI.INTFLAG.bit.RXC == 0 )
|
|
{
|
|
// Waiting Complete Reception
|
|
}
|
|
|
|
return sercom->SPI.DATA.bit.DATA; // Reading data
|
|
}
|
|
|
|
bool isBufferOverflowErrorSPI( Sercom *sercom )
|
|
{
|
|
return sercom->SPI.STATUS.bit.BUFOVF;
|
|
}
|
|
|
|
bool isDataRegisterEmptySPI( Sercom *sercom )
|
|
{
|
|
//DRE : Data Register Empty
|
|
return sercom->SPI.INTFLAG.bit.DRE;
|
|
}
|
|
|
|
//bool isTransmitCompleteSPI()
|
|
//{
|
|
// //TXC : Transmit complete
|
|
// return sercom->SPI.INTFLAG.bit.TXC;
|
|
//}
|
|
//
|
|
//bool isReceiveCompleteSPI()
|
|
//{
|
|
// //RXC : Receive complete
|
|
// return sercom->SPI.INTFLAG.bit.RXC;
|
|
//}
|