Difference between revisions of "PIC32 Examples"

From Steak Wiki
Jump to navigationJump to search
 
(One intermediate revision by the same user not shown)
Line 5: Line 5:
  
 
Goes like this:
 
Goes like this:
* TX puts something into buffer
+
* DMA puts something into SPIxTXREG buffer
* SDO outputs thing
+
* SDO outputs 'thing'
* SPIxRXREG now contains thing also
+
* SPIxRXREG now contains 'thing' also
 
* Transfer via DMA SPIxRXREG to memory
 
* Transfer via DMA SPIxRXREG to memory
 
* continue until DCHxSSIZ is complete (note that some MX are 8 bits for SSIZ, which means only 256 items, while some later are 16 bits)
 
* continue until DCHxSSIZ is complete (note that some MX are 8 bits for SSIZ, which means only 256 items, while some later are 16 bits)
If you can't keep up with the RX, and it overflows, there is a flag that is set. ROVR I think.
+
If you can't keep up with the RX, and it overflows, there is a flag that is set in SPIxSTAT. ROVR I think.
  
 +
NOTE: The RX SPI should be chen and cforce'd (called via software) first before the TX SPI, otherwise it might not sync up.
 +
 +
===Example Configuration===
 
<pre>
 
<pre>
 
void configureSPI_DMA (void){
 
void configureSPI_DMA (void){
 +
    DMACONbits.ON      = 1;            //global dma enable (already enabled, technically)
 
     //we put things in dma buffer, and it sends to spi, without cpu involvement
 
     //we put things in dma buffer, and it sends to spi, without cpu involvement
 
     //channel 1
 
     //channel 1
Line 40: Line 44:
 
     //DCH1SSA            = KVA_TO_PA(spiregisters);      //source address (has values)
 
     //DCH1SSA            = KVA_TO_PA(spiregisters);      //source address (has values)
 
     DCH1SSA            = KVA_TO_PA(testRGB);      //source address (has values)
 
     DCH1SSA            = KVA_TO_PA(testRGB);      //source address (has values)
    //DCH1SSA            = KVA_TO_PA(testsimple);  //this works when padding testsimple array with some zeros, but not if just 0x3,0x4,0x5
 
    //DCH1SSA            = KVA_TO_PA(&dmatoram[0]);      //source address (blank zeros)
 
    //DCH1DSA            = KVA_TO_PA(&SPI2BUF);          //destination address
 
 
     DCH1DSA            = KVA_TO_PA(&SPI2BUF);
 
     DCH1DSA            = KVA_TO_PA(&SPI2BUF);
 
     DCH1SSIZ            = 1000;  //9643          //source size (1 byte)
 
     DCH1SSIZ            = 1000;  //9643          //source size (1 byte)
Line 63: Line 64:
 
     DCH1INT;
 
     DCH1INT;
 
     IEC1bits.DMA1IE    = 1;            //enable interrupts
 
     IEC1bits.DMA1IE    = 1;            //enable interrupts
    DMACONbits.ON      = 1;            //global dma enable (already enabled, technically)
 
    DCH1CONbits.CHEN    = 1;            //enables channel
 
 
      
 
      
     //after neobit fills spiregisters, do this...?
+
     //call these to start dma
 +
    //DCH1CONbits.CHEN    = 1;            //enables channel
 
     //DCH1ECONbits.CFORCE = 1;            //run once
 
     //DCH1ECONbits.CFORCE = 1;            //run once
 
     IEC1;       
 
     IEC1;       

Latest revision as of 21:59, 1 November 2019

I need somewhere to put my scraps of code. These may or may not work.

DMA SPI

Also covered by peripheral libraries example. Must have RX and TX enabled (for MX). RX must empty buffer. Everything put into TX, goes into RX (they share buffer). Therefore, you must use two DMA channels to use SPI and DMA to SDO something.

Goes like this:

  • DMA puts something into SPIxTXREG buffer
  • SDO outputs 'thing'
  • SPIxRXREG now contains 'thing' also
  • Transfer via DMA SPIxRXREG to memory
  • continue until DCHxSSIZ is complete (note that some MX are 8 bits for SSIZ, which means only 256 items, while some later are 16 bits)

If you can't keep up with the RX, and it overflows, there is a flag that is set in SPIxSTAT. ROVR I think.

NOTE: The RX SPI should be chen and cforce'd (called via software) first before the TX SPI, otherwise it might not sync up.

Example Configuration

void configureSPI_DMA (void){
    DMACONbits.ON       = 1;            //global dma enable (already enabled, technically)
    //we put things in dma buffer, and it sends to spi, without cpu involvement
    //channel 1
    DCH1INT             = 0;           //disable all dma interrupts
    IEC1bits.DMA1IE     = 0x00;        //disable DMA channel 1 interrupts
    IFS1bits.DMA1IF     = 0x00;        //clear any existing dma flags
    DCH1CONbits.CHPRI   = 0b10;   //second priority 
    //this doesn't work
    //DCH1INTbits.CHCCIE  = 1;        //ENABLE not flag. Don't mix these up...
                                    //cell transfer status flag was the only one
                                    //going high, so set it to that instead of block.
                                    
    DCH1INTbits.CHBCIE  = 1;        //interrupt dma, when block transfer done. eq to DMA_EV_BLOCK
                                    //this didn't work. I put a watch on that register flag
                                    //but it never caught in the main loop. however, others do.
                                    //edit: this does work.
    DCH1ECONbits.CHSIRQ = 38;     //spi 2 transfer done (this activates the dma)
    //this below doesn't work
    //DCH1ECONbits.CHSIRQ = 49;     //EDIT:I think you use not SPI, but the DMA interrupts.
                                  //when a block transfer is done, you do another one.
                                  //there are a few interrupts, see DCH1INT, for what you
                                  //can use, and also the flags that are set can be watched.
    DCH1ECONbits.SIRQEN = 1;      //req'd for chsirq, in order to work
    DCH1CONbits.CHAEN   = 0;      //channel is automatically enabled, after transfer
    //Source, Destination, Source size, Dest Size, bytes transfer
    //DCH1SSA             = KVA_TO_PA(spiregisters);      //source address (has values)
    DCH1SSA             = KVA_TO_PA(testRGB);      //source address (has values)
    DCH1DSA             = KVA_TO_PA(&SPI2BUF);
    DCH1SSIZ            = 1000;  //9643          //source size (1 byte)
    DCH1DSIZ            = 1;           //destination size max
    DCH1SPTR;                          //pointer of where source is
    DCH1DPTR;
    DCH1CSIZ            = 1;           //bytes transferred on an event
    
                         //NOTE: This has to be equal to source, and dest, if both 
                         //source and dest are RAM. Not so for UART though.
    //priority,flag,enable (for interrupts)
    IPC9bits.DMA1IP = 0x00;             //clear priority
    IPC9bits.DMA1IS = 0x00;             //clear sub priority
    IPC9bits.DMA1IP = 4;                //set priority 5
    IPC9bits.DMA1IS = 2;   //clear sub priority
    DMACON;
    DMASTAT;
    DCH1CON;
    DCH1ECON;
    DCH1INT;
    IEC1bits.DMA1IE     = 1;            //enable interrupts
    
    //call these to start dma
    //DCH1CONbits.CHEN    = 1;            //enables channel
    //DCH1ECONbits.CFORCE = 1;            //run once
    IEC1;       
    IFS1;
    IPC9;
    
}

//rx dma
void configureSPIRXDMA(void){
 
    DCH2INT             = 0;           //disable all dma interrupts
    IEC1bits.DMA2IE     = 0x00;        //disable DMA channel 1 interrupts
    IFS1bits.DMA2IF     = 0x00;        //clear any existing dma flags
    DCH2CONbits.CHPRI   = 0b10;   //second priority 
    //this doesn't work
    //DCH1INTbits.CHCCIE  = 1;        //ENABLE not flag. Don't mix these up...
                                    //cell transfer status flag was the only one
                                    //going high, so set it to that instead of block.
                                    
    //DCH2INTbits.CHBCIE  = 1;        //interrupt dma, when block transfer done. eq to DMA_EV_BLOCK
                                    //this didn't work. I put a watch on that register flag
                                    //but it never caught in the main loop. however, others do.
                                    //edit: this does work.
    DCH2ECONbits.CHSIRQ = 39;     //spi 2 receive done (this activates the dma)
    //this below doesn't work
    //DCH1ECONbits.CHSIRQ = 49;     //EDIT:I think you use not SPI, but the DMA interrupts.
                                  //when a block transfer is done, you do another one.
                                  //there are a few interrupts, see DCH1INT, for what you
                                  //can use, and also the flags that are set can be watched.
    DCH2ECONbits.SIRQEN = 1;      //req'd for chsirq, in order to work
    DCH2CONbits.CHAEN   = 0;      //channel is automatically enabled, after transfer
    DCH2SSA             = KVA_TO_PA(&SPI2BUF);      //source address (has values)
    DCH2DSA             = KVA_TO_PA(spirxbuf);
    DCH2SSIZ            = 1;  //9643          //source size (1 byte)
    DCH2DSIZ            = 1000;           //destination size max
    DCH2SPTR;                          //pointer of where source is
    DCH2DPTR;
    DCH2CSIZ            = 1;           //bytes transferred on an event
    
                         //NOTE: This has to be equal to source, and dest, if both 
                         //source and dest are RAM. Not so for UART though.
  
    DCH2CONbits.CHCHNS = 0; //chain to channel higher up (1)
    DCH2CONbits.CHCHN  = 1; //enable chain channel
    IPC9bits.DMA2IP = 0x00;             //clear priority
    IPC9bits.DMA2IS = 0x00;             //clear sub priority
    IPC9bits.DMA2IP = 4;               
    IPC9bits.DMA2IS = 3;   
    DMACON;
    DMASTAT;
    DCH2CON;
    DCH2ECON;
    DCH2INT;
    //DMACONbits.ON       = 1;            //global dma enable (already enabled, technically)
    DCH2CONbits.CHEN    = 1;            //enables channel
    IEC1;       
    IFS1;
    IPC9;
    IEC1bits.DMA2IE = 1;        //enable dma interrupts
    IPC9bits.DMA2IP = 7;
    IPC9bits.DMA2IS = 3;
   
    
}

Enable Peripheral

void configureSPI(void){

    //we need to disable SPIROV flag in interrupt, otherwise transmit
    //mode will fail, as it expects receive to occur. we want
    //transmit only, which this particular ic doesn't have.
    
    
    
    //23.3.3.1
    IEC1;
    IFS1;
    IPC7; //(priority)
    IEC1bits.SPI2EIE     = 0;    //disable interrupts
    IEC1bits.SPI2RXIE    = 0;
    IEC1bits.SPI2TXIE    = 0;
    IEC1bits.SPI2EIE     = 0;    //enable general error flag (all three get flagged, in practice)
    IEC1bits.SPI2RXIE    = 0;    //EDIT: can't enable SPI interrupt when
                                 //DMA is being used... I knew this... but forgot.
    IPC7bits.SPI2IP      = 7;    //priority
    IPC7bits.SPI2IS      = 2;
    
    rData = SPI2BUF;
    
    //enable SPI
    SPI2CONbits.ON       = 0;    //stop & reset module
    SPI2BUF              = 0;    //clear buffer (rx/tx)
    SPI2CON;                     //missing enhanced mode...?
    //SPI2BRG = 80;       //gives us 2us (with pbclk div 1, we need ns which is lower      //brg for spi is divider of pbclk. So if pbclk is 80MHz, you do 80 to get 1MHz spi
    //SPI2BRG = 40; //not fast enough, about 500ns
    //SPI2BRG = 20; //20 doesnt work for some reason, but can go lower//22 550ns //25 - 650ns//30 //36
    //SPI2BRG   = 15; //325ns
    //SPI2BRG   = 10; //225ns
    SPI2BRG = 10;    // 8 is almost right, 9 doesn't work at all. some numbers don't work.
    //SPI2BRG = 6; //this is too fast. also 5 is too fast.
    //SPI2BRG   = 5; //225ns. that gives below for 1,2,3 bits respectively. Can use 8 bits.
    /*
     *  T0H - 225ns                   T0L - 450ns
     *  T1H - 675ns                   T1L - 675ns
     * 6us (micro) at gnd to latch == about 26.66 bits, let's say 32 bits at 225ns
     * EDIT: in practice, this didn't actually these speeds...
     */
    //SPI2BRG   = 4; //about 100-105ns. that gives below. More accurate, requires 16 bits for SPI.
    /*
     *  T0H - 315ns                   T0L - 420ns
     *  T1H - 735ns                   T1L - 630ns
     */
    
    
    SPI2STATbits.SPIROV  = 0;    //clear registers
    SPI2CONbits.MSTEN    = 1;    //master (not slave mode)
    SPI2STAT; //status
    
    
    SPI2CONbits.ON = 1;          //enable SPI
    
    
}