*** stock_iot-lab_M3/openwsn/spi.c Thu Apr 24 11:19:40 2014 --- riot-openwsn-wip/openwsn/spi.c Thu Apr 24 16:55:54 2014 *************** *** 0 **** --- 1,258 ---- + /** + \brief iot-lab_M3 definition of the "spi" bsp module (based on openmoteSTM32 code). + + \author Thomas Watteyne , February 2012. + \author Chang Tengfei , July 2012. + \author Alaeddine Weslati , January 2014. + */ + #include "stm32f10x_lib.h" + #include "stdio.h" + #include "stdint.h" + #include "string.h" + #include "spi.h" + #include "leds_ow.h" + + #include "rcc.h" + #include "nvic.h" + + #define ENABLE_DEBUG (0) + #include "debug.h" + + //=========================== defines ========================================= + + //=========================== variables ======================================= + + typedef struct { + // information about the current transaction + uint8_t* pNextTxByte; + uint8_t numTxedBytes; + uint8_t txBytesLeft; + spi_return_t returnType; + uint8_t* pNextRxByte; + uint8_t maxRxBytes; + spi_first_t isFirst; + spi_last_t isLast; + // state of the module + uint8_t busy; + #ifdef SPI_IN_INTERRUPT_MODE + // callback when module done + spi_cbt callback; + #endif + } spi_vars_t; + + volatile spi_vars_t spi_vars; + + //=========================== prototypes ====================================== + inline static void RESET_CLR(void) { GPIOC->BRR = 1<<1; } + inline static void RESET_SET(void) { GPIOC->BSRR = 1<<1; } + inline static void CSn_SET(void) { GPIOA->BSRR = 1<<4; } + inline static void CSn_CLR(void) { GPIOA->BRR = 1<<4; } + inline static void SLEEP_CLR(void) { GPIOA->BRR = 1<<2; } + + //=========================== public ========================================== + + void spi_init() { + // clear variables + memset((void*)&spi_vars,0,sizeof(spi_vars_t)); + + SPI_InitTypeDef SPI_InitStructure; + + //enable SPI1, GPIOA, GPIOB and GPIOC, Clock + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + + //Configure SPI-related pins: PA.5 as SCLK pin ,PA.6 as MISO pin, PA.7 as MOSI pin, PA.4 as /SEL pin + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_2; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + // force reset + RESET_CLR(); + CSn_SET(); + SLEEP_CLR(); + + for (uint16_t j=0;j<0xFFFF;j++); //small wait + + RESET_SET(); + + //Configure SPI1 + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Full-duplex synchronous transfers on two lines + SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//Master Mode + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8-bit transfer frame format + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //the SCK pin has a low-level idle state + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //the first rising edge on the SCK pin is the MSBit capture strobe, + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//Software NSS mode + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;//BaudRate Prescaler = 8 + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//data order with MSB-first + SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC Polynomial = 7 + SPI_Init(SPI1, &SPI_InitStructure); + + //enable SPI1 + SPI_Cmd(SPI1, ENABLE); + + #ifdef SPI_IN_INTERRUPT_MODE + //Configure NVIC: Preemption Priority = 1 and Sub Priority = 1 + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + #endif + } + + #ifdef SPI_IN_INTERRUPT_MODE + void spi_setCallback(spi_cbt cb) { + spi_vars.callback = cb; + } + #endif + + void spi_txrx(uint8_t* bufTx, + uint8_t lenbufTx, + spi_return_t returnType, + uint8_t* bufRx, + uint8_t maxLenBufRx, + spi_first_t isFirst, + spi_last_t isLast) { + + #ifdef SPI_IN_INTERRUPT_MODE + // disable interrupts + NVIC_RESETPRIMASK(); + #endif + + // register spi frame to send + spi_vars.pNextTxByte = bufTx; + spi_vars.numTxedBytes = 0; + spi_vars.txBytesLeft = lenbufTx; + spi_vars.returnType = returnType; + spi_vars.pNextRxByte = bufRx; + spi_vars.maxRxBytes = maxLenBufRx; + spi_vars.isFirst = isFirst; + spi_vars.isLast = isLast; + + // SPI is now busy + spi_vars.busy = 1; + + + // lower CS signal to have slave listening + if (spi_vars.isFirst==SPI_FIRST) { + GPIO_ResetBits(GPIOA, GPIO_Pin_4); + } + + #ifdef SPI_IN_INTERRUPT_MODE + // implementation 1. use a callback function when transaction finishes + + // write first byte to TX buffer + SPI_I2S_SendData(SPI1,*spi_vars.pNextTxByte); + + // re-enable interrupts + NVIC_SETPRIMASK(); + #else + // implementation 2. busy wait for each byte to be sent + // send all bytes + while (spi_vars.txBytesLeft>0) { + // write next byte to TX buffer + SPI_I2S_SendData(SPI1,*spi_vars.pNextTxByte); + + // busy wait on the interrupt flag + while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET); + + // clear the interrupt flag + SPI_I2S_ClearFlag(SPI1, SPI_I2S_FLAG_RXNE); + // save the byte just received in the RX buffer + switch (spi_vars.returnType) { + case SPI_FIRSTBYTE: + if (spi_vars.numTxedBytes==0) { + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + } + break; + case SPI_BUFFER: + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + spi_vars.pNextRxByte++; + break; + case SPI_LASTBYTE: + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + break; + } + // one byte less to go + spi_vars.pNextTxByte++; + spi_vars.numTxedBytes++; + spi_vars.txBytesLeft--; + } + + // put CS signal high to signal end of transmission to slave + if (spi_vars.isLast==SPI_LAST) { + GPIO_SetBits(GPIOA, GPIO_Pin_4); + } + + // SPI is not busy anymore + spi_vars.busy = 0; + #endif + } + + //=========================== private ========================================= + + //=========================== interrupt handlers ============================== + + kick_scheduler_t spi_isr() { + #ifdef SPI_IN_INTERRUPT_MODE + // save the byte just received in the RX buffer + switch (spi_vars.returnType) { + case SPI_FIRSTBYTE: + if (spi_vars.numTxedBytes==0) { + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + } + break; + case SPI_BUFFER: + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + spi_vars.pNextRxByte++; + break; + case SPI_LASTBYTE: + *spi_vars.pNextRxByte = SPI_I2S_ReceiveData(SPI1); + break; + } + + // one byte less to go + spi_vars.pNextTxByte++; + spi_vars.numTxedBytes++; + spi_vars.txBytesLeft--; + + if (spi_vars.txBytesLeft>0) { + // write next byte to TX buffer + SPI_SendData(SPI1,*spi_vars.pNextTxByte); + } else { + // put CS signal high to signal end of transmission to slave + if (spi_vars.isLast==SPI_LAST) { + GPIO_SetBits(GPIOA, GPIO_Pin_4); + } + // SPI is not busy anymore + spi_vars.busy = 0; + + // SPI is done! + if (spi_vars.callback!=NULL) { + // call the callback + spi_vars.callback(); + // kick the OS + return 1; + } + } + #else + while(1);// this should never happen + #endif + }