
SPI slave program to enable communication between the FPGA and the STM32L432 board.
Diff: DMA_SPI.cpp
- Revision:
- 15:791f35b0f220
- Parent:
- 14:7bbaafa22f8d
--- a/DMA_SPI.cpp Sun May 05 01:08:22 2019 +0000 +++ b/DMA_SPI.cpp Wed May 15 22:56:20 2019 +0000 @@ -30,6 +30,7 @@ startCommunication(); } +//-----------------------------------------------Step-5----------------------------------------------------------------------------------------------------------- /* Starting DMA communication according to STM32L432 Reference Manual p1317-p1318*/ void startCommunication() { @@ -149,91 +150,97 @@ void SPI_DMA_SLAVE_init() { - RCC->AHB2ENR|= (RCC_AHB2ENR_GPIOAEN); //GPIO A clock enable - RCC->AHB2ENR |= (RCC_AHB2ENR_GPIOBEN); - RCC->APB2ENR|=RCC_APB2ENR_SPI1EN; //Enable SPI1 Clock + //-----------------------------------------------Step-1----------------------------------------------------------------------------------------------------------- + RCC->AHB2ENR|= (RCC_AHB2ENR_GPIOAEN); //GPIO A clock enable by setting the GPIOAEN bit in the RCC_AHB2ENR register + RCC->AHB2ENR |= (RCC_AHB2ENR_GPIOBEN); //GPIO B clock enable by setting the GPIOBEN bit in the RCC_AHB2ENR register + RCC->APB2ENR|=RCC_APB2ENR_SPI1EN; //Enable SPI1 Clock by setting the SPI1EN bit in the RCC_APB2ENR register - //SET SCK, MISO, MOSI and CS pins + //-----------------------------------------------Step-2----------------------------------------------------------------------------------------------------------- + //SET SCK, MISO, MOSI and CS pins GPIOA->MODER|=( - (2u<<(2*SCK_slave)) - |(2u<<(2*MISO_slave)) - |(2u<<(2*MOSI_slave)) + (2u<<(2*SCK_slave)) //Set pin 1 in the MODER register of port A as alternate function + |(2u<<(2*MISO_slave)) //Set pin 6 in the MODER register of port A as alternate function + |(2u<<(2*MOSI_slave)) //Set pin 7 in the MODER register of port A as alternate function //|(2u<<(2*4)) ); //Set PB_0 to alternate function - GPIOB->MODER |= (2u<<0); - + GPIOB->MODER |= (2u<<0); //Set pin 0 in the MODER register of port B as alternate function + + //-----------------------------------------------Step-3----------------------------------------------------------------------------------------------------------- //SET pins to function as SPI pins - GPIOA->AFR[0]|=( - (5u<<(4*SCK_slave)) - |(5u<<(4*MISO_slave)) - |(5u<<(4*MOSI_slave)) + GPIOA->AFR[0]|=( + (5u<<(4*SCK_slave)) //Set the alternate function of pin 1 as SPI clock pin by writing 1001 to the lower part of the AFR register of port A. + |(5u<<(4*MISO_slave)) //Set the alternate function of pin 6 as SPI MISO pin by writing 1001 to the lower part of the AFR register of port A. + |(5u<<(4*MOSI_slave)) //Set the alternate function of pin 7 as SPI clock pin by writing 1001 to the lower part of the AFR register of port A. //|(5u<<(4*4)) ); //Select SPI1_SSEL alternate function - GPIOB->AFR[0] |= (5u<<(4*0)); - + GPIOB->AFR[0] |= (5u<<(4*0)); //Set the alternate function of pin 0 as SPI slave select pin by writing 1001 to the lower part of the AFR register of port B. + + //-----------------------------------------------Step-4----------------------------------------------------------------------------------------------------------- SET_SPI1_CR1_BR_BITS(); //baud rate bits set 1/16 giving 1MHz SCK frequency + //-----------------------------------------------Step-5----------------------------------------------------------------------------------------------------------- SET_SPI1_CR1_CPOL_BIT(); //CPOL = 1 SET_SPI1_CR1_CPHA_BIT(); //CPHA = 1 - + //-----------------------------------------------Step-6----------------------------------------------------------------------------------------------------------- SET_SPI1_CR2_DS_BITS(); //Data Size = 16 bits // SET_SPI1_CR2_RXDMAEN_BIT(); //Rx buffer DMA enable - // SET_SPI1_CR2_TXDMAEN_BIT(); //Tx buffer DMA enable - - + // SET_SPI1_CR2_TXDMAEN_BIT(); //Tx buffer DMA enable } - - + //SET_DMA1_CH2_CCR_PINC_BIT(); //Peripheral increment mode + // SET_DMA1_CH3_CCR_PINC_BIT(); //Peripheral increment mode + void initDMA() { + //-----------------------------------------------Step-1----------------------------------------------------------------------------------------------------------- RCC->AHB1ENR|= (RCC_AHB1ENR_DMA1EN); //Enable the DMA1 clock + //-----------------------------------------------Step-2----------------------------------------------------------------------------------------------------------- DMA1_CH2_DISABLE(); //Disable DMA channel 2 DMA1_CH3_DISABLE(); //Disable DMA channel 3 SET_DMA1_SPI1RX_CSELR_BITS(); //Select SPI1_Rx on DMA1 Channel 2 SET_DMA1_SPI1TX_CSELR_BITS(); //Select SPI1_Tx on DMA1 Channel 3 - + + //-----------------------------------------------Step-3----------------------------------------------------------------------------------------------------------- //-----------------------------------------------Receive----------------------------------------------------- - CLEAR_DMA1_CH2_CCR_DIR_BIT(); //Peripheral->Memory - SET_DMA1_CH2_CCR_PSIZE_BITS(); //16 bits - SET_DMA1_CH2_CCR_MSIZE_BITS(); //16 bits - SET_DMA1_CH2_CCR_MINC_BIT(); //Memory increment mode - //SET_DMA1_CH2_CCR_PINC_BIT(); //Peripheral increment mode - SET_DMA1_CH2_CCR_TCIE_BIT(); //Transfer complete interrupt enable - SET_DMA1_CH2_CCR_CIRC_BIT(); //Circular Buffer mode + CLEAR_DMA1_CH2_CCR_DIR_BIT(); //Direction bit: 0 = Peripheral->Memory. Data will be loaded from SPI data register to the specified variable + SET_DMA1_CH2_CCR_PSIZE_BITS(); //peripheral size bit: 1 = 16 bits. The size is set to 16 bits as thats the data size SPI will work in. + SET_DMA1_CH2_CCR_MSIZE_BITS(); //Memory size bit: 1 = 16 bits. The size is set to 16 bits as data coming from SPI is 16 bits wide + SET_DMA1_CH2_CCR_MINC_BIT(); //Memory increment mode but: 1 = Increment memory after each transaction. Used when multiple transaction are done before interrupt occurs + SET_DMA1_CH2_CCR_TCIE_BIT(); //Transfer complete interrupt enable: 1 = enabled. Allows DMA to interrupt software when number of transaction has occured. + SET_DMA1_CH2_CCR_CIRC_BIT(); //Circular Buffer mode: 1 = enabled. After n transaction, the address is reset to starting memory address automatically. SET_DMA1_CH2_CCR_PL_BITS(); //Priority Level = Highest - DMA1_Channel2->CNDTR = 12; //number of data to transfer from the peripheral to memory. + DMA1_Channel2->CNDTR = 12; //number of data to transfer from the peripheral to memory before interrupt occurs. DMA1_Channel2->CPAR = (int32_t)&SPI1->DR; //Source Adddress = SPI data register - DMA1_Channel2->CMAR = (int32_t)&received_data[0]; //Destination address = received_data array + DMA1_Channel2->CMAR = (int32_t)&received_data[0]; //Destination address = received_data array. //-----------------------------------------------Receive----------------------------------------------------- + + //-----------------------------------------------Transmission------------------------------------------------ - SET_DMA1_CH3_CCR_DIR_BIT(); //Memory->Peripheral - SET_DMA1_CH3_CCR_PSIZE_BITS(); //16 bits - SET_DMA1_CH3_CCR_MSIZE_BITS(); //16 bits + SET_DMA1_CH3_CCR_DIR_BIT(); //Direction bit: 1 = Memory->Peripheral. Data will be sent from variable to SPI data register for transmission + SET_DMA1_CH3_CCR_PSIZE_BITS(); //peripheral size bit: 1 = 16 bits. The size is set to 16 bits as thats the data size SPI will work in. + SET_DMA1_CH3_CCR_MSIZE_BITS(); //Memory size bit: 1 = 16 bits. The size is set to 16 bits as data coming from SPI is 16 bits wide SET_DMA1_CH3_CCR_MINC_BIT(); //Memory increment mode - // SET_DMA1_CH3_CCR_PINC_BIT(); //Peripheral increment mode SET_DMA1_CH3_CCR_TCIE_BIT(); //Transfer complete interrupt enable SET_DMA1_CH3_CCR_CIRC_BIT(); //Circular Buffer mode SET_DMA1_CH3_CCR_PL_BITS(); //Priority Level = Highest - DMA1_Channel3->CNDTR = 12; //number of data to transfer from memory to the peripheral + DMA1_Channel3->CNDTR = 12; //number of data to transfer from memory to the peripheral to be transmitted. DMA1_Channel3->CPAR = (int32_t)&SPI1->DR; //Destination address = SPI data register - DMA1_Channel3->CMAR = (int32_t)&data_to_transmit[0]; //Source address = data_to_transmit + DMA1_Channel3->CMAR = (int32_t)&data_to_transmit[0]; //Source address = data_to_transmit: Address from which data will be loaded to the SPI data register for transmission //-----------------------------------------------Transmission------------------------------------------------ - - - NVIC->ISER[0] |= (1u<<12); //Enable DMA1 channel 2 interrupt - NVIC->ISER[0] |= (1u<<13); //Enable DMA1 channel 3 interrupt +//-----------------------------------------------Step-4----------------------------------------------------------------------------------------------------------- + //Enable DMA1 channel 2 and 3 interrupts + NVIC->ISER[0] |= (1u<<12); + NVIC->ISER[0] |= (1u<<13); NVIC_EnableIRQ(DMA1_Channel2_IRQn); - NVIC_EnableIRQ(DMA1_Channel3_IRQn); - + NVIC_EnableIRQ(DMA1_Channel3_IRQn); } @@ -241,16 +248,11 @@ extern "C" void DMA1_Channel2_IRQHandler(void) { uint16_t n; - CLEAR_DMA1_CH2_IFCR_GFLAG(); //Clear Global Interrupt flag - for(int x = 0; x <= 11; x++) { - - n = received_data[x]; - n &= ~(8191); //remove first 13 bits - n = n >> 13; //shift by right by 13 - SampleFIFO[pointerFS][x] = received_data[x]; - // printf("%d \n\r", n); + CLEAR_DMA1_CH2_IFCR_GFLAG(); //Clear Global Interrupt flag so that the nterrupt can occur again once a new batch of data is received. + for(int x = 0; x <= 11; x++) { //run the for loop to read new data from the array that the SPI uses to save the received data to a new array to avoid overwritting + SampleFIFO[pointerFS][x] = received_data[x]; //Just move the data from one array to the other. } - newDataFlag = 1; + newDataFlag = 1; //Once new data has been read set this flag to notify software that new data is received so that it proceeds with processing it. }