chipKIT® Development Platform

Inspired by Arduino™

Fubarino Mini SPI Frequency , MCP4822 DAC 1MHz+

Created Fri, 10 Jul 2015 13:51:26 +0000 by Gary Freegard


Gary Freegard

Fri, 10 Jul 2015 13:51:26 +0000

Hello I have a need to use both channels of a MCP4822 in a bespoke circuit and this is the first time that I have had to use SPI.

After several attempts using various examples from the internet, it didn’t help that PPS wasn’t working the way it should. In the begin method (SPI .cpp) I had to make the following changes.

// mapPps(pinMISO, ppsMISO);
mapPps(18, PPS_OUT_SDO2);
    //mapPps(pinMOSI, ppsMOSI);
mapPps(6, PPS_IN_SDI2);

The strange thing is that the output is on pin 9 :?

To test the circuit out, the code outputs two sine waves that can be at the same frequencies or different ones. Uses an array that holds the sine wave points, and have a routine to go through this at different step sizes.

The frequency is the inverse of the time taken to start the transfer to the start of the next transfer. Measured by using the CS pin.

The max frequency is 195.9KHz, this is using SPI.transfer which is written for 8bits, inside the void loop() not in a separate while loop and the SPI was set to run at 20MHz (just over). The SPI library doesn’t have any 16 or 32 bit methods.

I then decided to see how far I could push the system. So changed the code to one channel . 8bit SPI.transfer 444.23KHz 8bit SPI.write 685.2KHz

Then decided on trying to get 16bit transfer to work, which does make a bit of difference :D

16bit SPI.transfer16 592.6KHz 16bit SPI.write16 631.55KHz 16bit SPI.writeonly16 774.16KHz 16bit optimise order 1116.23KHz

Changes made to SPI.h, just showing the 8bit methods, the 16bit just has the uint8_t changed to uint16_t. Plus the methods need to be defined.

uint8_t SPIClass::transfer(uint8_t _data)
{
	while ((spi->sxStat.reg & (1 << _SPISTAT_SPITBE)) == 0 );
	spi->sxBuf.reg = _data;
	while ((spi->sxStat.reg & (1 << _SPISTAT_SPIRBF)) == 0 );
	return spi->sxBuf.reg;
}

uint8_t SPIClass::write(uint8_t _data)
{
	spi->sxBuf.reg = _data;
	while ((spi->sxStat.reg & (1 << _SPISTAT_SPIRBF)) == 0 )
	{}
	return 0;
}

void SPIClass::writeonly16(uint16_t _data)
{
	spi->sxBuf.reg = _data;
}

Had to make the following change to SPI.cpp, to select 16 or 8 bit data , also needs to be defined.

void SPIClass::setDataSize(uint8_t size)
{
	spi->sxCon.clr = (1 << _SPICON_ON);
	spi->sxCon.clr = 0xC00;
	spi->sxCon.set = size<<0x8;
	spi->sxCon.set = (1 << _SPICON_ON);
}

Optimization I changed the port writes from PORTBbits to PORTB. I had noticed that once the data is written to the SPI buffer the program can continue, and that there is a slight delay from writing to the buffer and the commencement of data transfer. So moved the PORTB write and the routine for getting sine wave value to just after the buffer write. Had to add 20 plus Nop() prior to the next PORTB write to get the code to work. FROM

while(1){
PORTBbits.RB1 = 1;
PORTBbits.RB3 = 0;
pos = check(pos,step, target, target1);
SPI.write16(sine[pos]|0x1000);
PORTBbits.RB1 = 0;
PORTBbits.RB3 = 1;

TO

pos = check(pos,step, target, target1);
while(1){
 	SPI.writeonly16(sine[pos]|0x1000);
	PORTB = 0x0002;
  	pos = check(pos,step, target, target1);
 	SPI.wait();//Has 21 Nop();
	PORTB = 0x0008;
	}

It helped that I had a digital oscilloscope by the side of me so that I could see what was happening when I was tweaking the code :D .

Gary


majenko

Fri, 10 Jul 2015 15:42:16 +0000

SPI is old code and rather broken. You should be using DSPI (bundled with MPIDE and UECIDE) which has not only 16 and 32 bit SPI transfer modes in it, but also "enhanced buffer" mode which makes for even faster block transfers.


Gary Freegard

Mon, 13 Jul 2015 15:02:45 +0000

Hi

I did try DSPI but unfortunately it appears to be broken, using your program (UECIDE 08.7z36)

UECIDE\cores\chipKIT\libraries\DSPI\DSPI.cpp:1094:1: error: 'DSPI1' does not name a type

So had to used SPI. Also DSPI uses the same procedure in its transfer/write methods as SPI does, though it does have 8/16/32 option.

And I was just showing what could be acheived with a little bit of investigation/creativeness and modification of the libraries. Libraries are a good resource for starting with but they may not give you what i.e. performance as in this case.

Using the enhanced mode would then probably mean the use of interrupts, which do lead to a slight drop in performance. I am not saying that it wouldnt be possible to achieve a similar level of performance but for me it would mean looking into something that I currently dont require, maybe in the future.


majenko

Mon, 13 Jul 2015 15:26:36 +0000

How were you using the DSPI library? The following works fine:

#include <DSPI.h>

DSPI1 spi;

void setup() {
	spi.begin();
}

void loop() {
}

The enhanced mode transfer is available in the block transfer functions, for instance the 8-bit block transfer function has this:

void
DSPI::transfer(uint16_t cbReq, uint8_t * pbSnd) {
#ifdef ENH_BUFFER
    pspi->sxCon.set = 1<<ENH_BUFFER;
    uint16_t toWrite = cbReq;
    uint16_t toRead = cbReq;
    uint16_t wPos = 0;

    while (toWrite > 0 || toRead > 0) {
        if (toWrite > 0) {
            if ((pspi->sxStat.reg & (1<<_SPISTAT_SPITBF)) == 0) {
                pspi->sxBuf.reg = pbSnd[wPos++];
                toWrite--;
            }
        }
        if (toRead > 0) {
            if ((pspi->sxStat.reg & (1<<_SPISTAT_SPIRBE)) == 0) {
                (void) pspi->sxBuf.reg;
                toRead--;
            }
        }
    }
    pspi->sxCon.clr = 1<<ENH_BUFFER;
#else

    for (cbCur = cbReq; cbCur > 0; cbCur--) {
        transfer(*pbSnd++);
    }
#endif
}

Unfortunately there aren't 16- and 32-bit block transfer functions at the moment, but I'm sure you could take the 8-bit one and make it 16-bit...


Gary Freegard

Mon, 13 Jul 2015 17:02:52 +0000

Hi

Whoops, copy and pasted an example, and it had DSPI0 spi; not DSPI1 spi; :oops:

But just tried your example and still doesn't work :(

DSPI.cpp:1094:1: error: 'DSPI1' does not name a type

Tried it with SDXL selected and it works. Any ideas?

There are 8,16 and 32 bit transfer (appears to be) .

setTransferSize(uint8_bits)

uint32_t transfer(uint32_t)

majenko

Mon, 13 Jul 2015 17:19:49 +0000

Which board are you working with? DSPI1 relies on the DSPI1 definitions existing in the configuration for the board you have selected.

Edit: note to self: READ THE TITLE!!!

Ok, so the fubarino Mini... let me check the defs... Which version of UECIDE are you on?

The Mini only has one DSPI port enabled, which is why it's not liking DSPI1... Even though it seems to have DSPI1 definitions in there, though I don't know if they are correct or not...

#define NUM_DSPI_PORTS      1
...
#define _DSPI0_BASE         _SPI1_BASE_ADDRESS
#define _DSPI0_ERR_IRQ      _SPI1_ERR_IRQ
#define _DSPI0_RX_IRQ       _SPI1_RX_IRQ
#define _DSPI0_TX_IRQ       _SPI1_TX_IRQ
#define _DSPI0_VECTOR       _SPI_1_VECTOR
#define _DSPI0_IPL_ISR      IPL3SOFT
#define _DSPI0_IPL          3
#define _DSPI0_SPL          0

#define _DSPI0_MISO_IN      PPS_IN_SDI1
#define _DSPI0_MISO_PIN     19
#define _DSPI0_MOSI_OUT     PPS_OUT_SDO1
#define _DSPI0_MOSI_PIN     18

/* SPI2
 * Note SCK2 only comes out B15, which is Arduino pin 4
 */
#define _DSPI1_BASE         _SPI2_BASE_ADDRESS
#define _DSPI1_ERR_IRQ      _SPI2_ERR_IRQ
#define _DSPI1_RX_IRQ       _SPI2_RX_IRQ
#define _DSPI1_TX_IRQ       _SPI2_TX_IRQ
#define _DSPI1_VECTOR       _SPI_2_VECTOR
#define _DSPI1_IPL_ISR      IPL3SOFT
#define _DSPI1_IPL          3
#define _DSPI1_SPL          0

#define _DSPI1_MISO_IN      PPS_IN_SDI2
#define _DSPI1_MISO_PIN     MISO
#define _DSPI1_MOSI_OUT     PPS_OUT_SDO2
#define _DSPI1_MOSI_PIN     MOSI

I guess that NUM_DSPI_PORTS should really be 2 not 1... I'll have to check with Brian if there's a reason for that being 1 or not...


Gary Freegard

Mon, 13 Jul 2015 17:38:49 +0000

Hi

Just found this on the forum, says the same as you

[url]http://chipkit.net/forum/viewtopic.php?t=2444#p9293[/url]

And when I set it to 2 it works :D

Edit: By works I meant it compiled and uploaded, but nothing from the DAC. No spi data out, but there is a clock out from pin 4. Obviously the ppsMap for SPI hasnt been setup correctly or at all.


Gary Freegard

Tue, 14 Jul 2015 16:22:31 +0000

Hi

I have managed to get it to work using

spi.begin(6,18);

Again the data out is on pin 9 not 18 :?

So far the fastest that I can get is 103KHz for an 8 bit stereo signal.

Think I might stay with SPI library for now.