PIC32 Examples
From Steak Wiki
Jump to navigationJump to searchI 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 }