SPI slave program to enable communication between the FPGA and the STM32L432 board.

Dependencies:   mbed

DMA_SPI.cpp

Committer:
Zbyszek
Date:
2019-04-19
Revision:
13:c7e8e277f884
Parent:
12:3e7da86a49ff
Child:
14:7bbaafa22f8d

File content as of revision 13:c7e8e277f884:

#include "mbed.h"
#include "DMA_SPI.h"

int16_t data_to_transmit[12];
int16_t received_data[12];
int16_t IMU_Data_Array[12];


int16_t SampleFIFO[10][12];
extern int pointerOS = 0;
extern int pointerNS = 0;
extern int pointerFS = 0;
extern char newDataFlag = 0;
volatile extern char dataRequestFlag = 0;
volatile extern char dataLoadedFlag = 0;


void SPI_DMA_init() {

    
    //Deinitialise
    SPI_DMA_SLAVE_deinit();
    deinitDMA();
    
    //Initialise
    initDMA();
    SPI_DMA_SLAVE_init(); 
    
    //Start DMA communication
    startCommunication();     
}    

/* Starting DMA communication according to STM32L432 Reference Manual p1317-p1318*/
void startCommunication() {
    
    SET_SPI1_CR2_RXDMAEN_BIT();                                                 //Enable RX DMA buffer
    DMA1_CH3_ENABLE();                                                          //Enable DMA channel 3      
    DMA1_CH2_ENABLE();                                                          //Enable DMA channel 2
    SET_SPI1_CR2_TXDMAEN_BIT();                                                 //Enable TX DMA buffer              
    SPI1_ENABLE();                                                              //SPI module enabled
}


//====================================================DEINITIALISE=========================================================================
void SPI_DMA_SLAVE_deinit() {
    //Disable the clocks
    //RCC->AHB2ENR &= ~(RCC_AHB2ENR_GPIOAEN);                                      
    //RCC->APB2ENR &=  ~(RCC_APB2ENR_SPI1EN);      
    //Clear pin settings
    
    
    GPIOA->MODER&=~(                                                             //clear GPIOB
            (3u<<(2*SCK_slave))
            |(3u<<(2*MISO_slave))
            |(3u<<(2*MOSI_slave))
            |(3u<<(2*4))
                );
            
          
     GPIOB->MODER &= ~(2u<<0);
    
    GPIOA->AFR[0]&=~(                                                            //clear alternate function selector bits
            (0x0f<<(4*SCK_slave))
            |(0x0f<<(4*MISO_slave))
            |(15u<<(4*MOSI_slave))
            //|(15u<<(2*4))                                                     //Thhis is why the UART was not working
            );
           
    GPIOB->AFR[0] &= ~(15u<<(4*0));
    
    //Clear SPI bits
    SPI1_DISABLE();
    CLEAR_SPI1_CR1_MSTR_BIT();
    CLEAR_SPI1_CR1_BR_BITS();
    CLEAR_SPI1_CR1_SSM_BIT();
    CLEAR_SPI1_CR1_SSI_BIT();
    CLEAR_SPI1_CR1_CPOL_BIT();
    CLEAR_SPI1_CR1_CPHA_BIT();
    
    
    CLEAR_SPI1_CR2_DS_BITS();
    CLEAR_SPI1_CR2_RXDMAEN_BIT();
    CLEAR_SPI1_CR2_TXDMAEN_BIT();
    CLEAR_SPI1_CR2_RXEIE_BIT();
    CLEAR_SPI1_CR2_TXEIE_BIT();
    
    CLEAR_SPI1_CR1_CRC_BIT();
    
     RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
     RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST;
}

void deinitDMA() {
    //RCC->AHB1ENR &= ~(RCC_AHB1ENR_DMA1EN);                                      //Disable the DMA1 clock
    RCC->AHB1RSTR |= RCC_AHB1RSTR_DMA1RST;
    RCC->AHB1RSTR &= ~RCC_AHB1RSTR_DMA1RST;
    
    //Disable channels
    DMA1_CH2_DISABLE();
    DMA1_CH3_DISABLE();
    
    CLEAR_DMA1_SPI1RX_CSELR_BITS();                                             //deselect SPI1_Rx on DMA1 Channel 2
    CLEAR_DMA1_SPI1TX_CSELR_BITS();                                             //deselect SPI1_Tx on DMA1 Channel 3
     
                    
//-----------------------------------------------Receive-----------------------------------------------------                       
   //Clear configuration bits                     
   CLEAR_DMA1_CH2_CCR_DIR_BIT();                                                
   CLEAR_DMA1_CH2_CCR_PSIZE_BITS();
   CLEAR_DMA1_CH2_CCR_MSIZE_BITS();
   CLEAR_DMA1_CH2_CCR_MINC_BIT();
   CLEAR_DMA1_CH2_CCR_PINC_BIT();
   CLEAR_DMA1_CH2_CCR_TCIE_BIT();
   CLEAR_DMA1_CH2_CCR_CIRC_BIT();
   CLEAR_DMA1_CH2_CCR_MEM2MEM_BIT();
   CLEAR_DMA1_CH2_CCR_PL_BITS();
   CLEAR_DMA1_CH2_CCR_TEIE_BIT();
   
   CLEAR_DMA1_CH2_CNDTR_BITS();
   CLEAR_DMA1_CH2_CPAR_BITS();
   CLEAR_DMA1_CH2_CMAR_BITS();
//-----------------------------------------------Receive-----------------------------------------------------   
    
//-----------------------------------------------Transmission------------------------------------------------  
    //Clear configuration bits 
    CLEAR_DMA1_CH3_CCR_DIR_BIT();
    CLEAR_DMA1_CH3_CCR_PSIZE_BITS();
    CLEAR_DMA1_CH3_CCR_MSIZE_BITS();
    CLEAR_DMA1_CH3_CCR_MINC_BIT();
    CLEAR_DMA1_CH3_CCR_PINC_BIT();
    CLEAR_DMA1_CH3_CCR_TCIE_BIT();
    CLEAR_DMA1_CH3_CCR_CIRC_BIT();
    CLEAR_DMA1_CH3_CCR_MEM2MEM_BIT();
    CLEAR_DMA1_CH3_CCR_PL_BITS();
    CLEAR_DMA1_CH3_CCR_TEIE_BIT();
    
    CLEAR_DMA1_CH3_CNDTR_BITS();
    CLEAR_DMA1_CH3_CPAR_BITS();
    CLEAR_DMA1_CH3_CMAR_BITS();
    
//-----------------------------------------------Transmission------------------------------------------------    
    
    NVIC->ISER[0]&= ~(1u<<12);                                                   //Disable DMA1 channel 2 interrupt                                                   
    NVIC->ISER[0]&= ~(1u<<13);                                                   //Disable DMA1 channel 3 interrupt
      
}
//====================================================DEINITIALISE=========================================================================



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

   //SET SCK, MISO, MOSI and CS pins 
    GPIOA->MODER|=(                                                             
            (2u<<(2*SCK_slave))
            |(2u<<(2*MISO_slave))
            |(2u<<(2*MOSI_slave))
            //|(2u<<(2*4))
                );
    //Set PB_0 to alternate function
    GPIOB->MODER |= (2u<<0);
                
    //SET pins to function as SPI pins
    GPIOA->AFR[0]|=(                                                             
            (5u<<(4*SCK_slave))
            |(5u<<(4*MISO_slave))
            |(5u<<(4*MOSI_slave))
            //|(5u<<(4*4))
                );
    
    //Select SPI1_SSEL alternate function          
    GPIOB->AFR[0] |= (5u<<(4*0));
                
    SET_SPI1_CR1_BR_BITS();                                                     //baud rate bits set 1/16 giving 1MHz SCK frequency
    SET_SPI1_CR1_CPOL_BIT();                                                    //CPOL = 1
    SET_SPI1_CR1_CPHA_BIT();                                                    //CPHA = 1                                                  
    
    
    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

    
}



void initDMA() {
    RCC->AHB1ENR|= (RCC_AHB1ENR_DMA1EN);                                        //Enable the DMA1 clock
    
    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
                    
//-----------------------------------------------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
   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->CPAR = (int32_t)&SPI1->DR;                                   //Source Adddress = SPI data register
    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_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->CPAR = (int32_t)&SPI1->DR;                                   //Destination address = SPI data register
    DMA1_Channel3->CMAR = (int32_t)&data_to_transmit[0];                            //Source address = data_to_transmit
//-----------------------------------------------Transmission------------------------------------------------    
    
    
    NVIC->ISER[0] |= (1u<<12);                                                   //Enable DMA1 channel 2 interrupt                                                   
    NVIC->ISER[0] |= (1u<<13);                                                   //Enable DMA1 channel 3 interrupt
    NVIC_EnableIRQ(DMA1_Channel2_IRQn);
    NVIC_EnableIRQ(DMA1_Channel3_IRQn);
                      
}


//Interrupt Handler for DMA1 Channel 2
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);
    }
    newDataFlag = 1;
}


//Interrupt Handler for DMA1 Channel 3
extern "C" void DMA1_Channel3_IRQHandler(void) {     
    if(DMA1->ISR&(1u<<9)) {                                                    //Check whteher data transmit transfer is complete  
        //Read data from the array that stores received data
        if(dataRequestFlag == 1 && dataLoadedFlag == 1) {
            for(int x = 0; x <= 11; x++) {
                if(x < 7) {                                                     //Data is only loaded in first 7 places
                    if(x == 0) {                                                //IMU ID is loaded in array position 0
                        data_to_transmit[x] = IMU_Data_Array[x];                 //Load the IMU data for transmission
                       // data_to_transmit[x] = 1;                                //Test Input
                    }
                    else {                                                      //Rest is loaded in the following order: x, y, z
                        data_to_transmit[x] = IMU_Data_Array[x];                 //Load the IMU data for transmission
                        //data_to_transmit[x] = 48+x;                             //Test Input
                    }
                }
                else {                                                          //After 7 positions have been filled, the rest is filled with zeros
                    data_to_transmit[x] = 0;                                    //Above 6 there is nothing more to send so send zeros.
                } 
            }
            dataRequestFlag = 0;                                                //Data request has been fulfilled and therefore clear the flag
        }
        else {                                                                  //if the two flags arent 1 then load this transmission with zeros
             for(int x = 0; x <= 11; x++) {
                data_to_transmit[x] = 0;
            } 
        }
        CLEAR_DMA1_CH3_IFCR_GFLAG();                                            //Clear global channel interrupt flag for channel 3
     }                                                                          //Clear Global Interrupt flag             
}