Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: DMA with OLED and DAC

  1. #1
    Senior Member
    Join Date
    Dec 2014
    Posts
    134

    DMA with OLED and DAC

    I am currently trying to speed up communication on my project by using DMA. It appears when I use the test example for the OLED_ssd1306 library it works fine, but when I try to use my spi DAC things completely stop. Am I supposed to use 2 different spi busses to realize this? Where can I find more info on how to go about this?

  2. #2
    Senior Member
    Join Date
    Dec 2014
    Posts
    134
    Here is a code snippet of my current stripped down test:
    #include <SPI.h>
    #include <Adafruit_GFX2.h>
    #include <OLED_SSD1306.h>

    #define OLED_DC 9
    #define OLED_CS 10
    #define OLED_RESET 14
    OLED_SSD1306 display(OLED_CS, OLED_DC, OLED_RESET);

    #define DAC_CS 15 // this is the part I have no idea about
    #define DAC_DATA 7 // what can I do to let the OLED use DMA on the hardware SPI pins
    #define DAC_CLK 8 //14 // and get the dac to work?

    byte totalWaves = 4;
    word wave[4][2];
    word wavePhase = 0;

    void setup() {
    display.begin();
    display.setBitrate(24000000);

    pinMode(DAC_CS, OUTPUT);
    digitalWrite(DAC_CS, HIGH);
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    }


    void loop(){
    for (int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, WHITE);
    display.display();
    }
    display.clearDisplay();

    DACoutSPI();
    }


    void DACoutSPI(){ //SPI DAC write
    for(byte channel = 0; channel < totalWaves; channel++){
    wave[channel][wavePhase] = random(4096);

    digitalWrite(DAC_CS, LOW);
    byte formatDacMSB = (channel<<6 | B00010000 | ((highByte(wave[channel][wavePhase])) & B00001111));
    byte formatDacLSB = (lowByte(wave[channel][wavePhase]));
    SPI.transfer(formatDacMSB);
    SPI.transfer(formatDacLSB);
    digitalWrite(DAC_CS,HIGH);
    }
    }

  3. #3
    Senior Member
    Join Date
    Feb 2013
    Posts
    563
    sumotoy will know more about potential conflicts, but you may just have configured SPI incorrectly?

    this for instance

    Code:
    #define DAC_CLK 8
    obviously doesn't look right. it should be either 13 or 14, i suppose (ie SPI SCK). 8 is DIN/MISO. looking at commonInit() in OLED_SSD1306.cpp, the library defaults to

    SCK : 13, DOUT/MOSI: 11

    is your display wired like this? or did you move things to pins 14 and 7 (presumably no, seeing that OLED_RESET = 14)?

    as a first step, i'd make sure the OLED and DAC share the same SCK and MOSI lines. presumably that would be

    Code:
    #define DAC_DATA 11
    #define DAC_CLK 13
    SPI.begin() is already invoked by display.begin(), so it's not needed again. if things still fail, ... doesn't look like the library features transactions.

  4. #4
    Senior Member
    Join Date
    Dec 2014
    Posts
    134
    I guess one of the things that is confusing to me is that if the DOUT/MOSI pin is sending SPI - DMA to OLED, then if I want to write out the word to the SPI DAC on the same pin, would there even be a performance gain? Isn't the point to be able to let the DMA do its thing through that pin while the micro controller does other stuff that doesn't touch that pin? Thus I was trying to figure out if I can use the greyed out secondary SPI pins on the reference card to write out to the DAC so that they can be as independent as possible.

    I am trying to find a "dummies guide" to getting started with DMA on the teensy and everything I find is not very introductory, its mainly people talking about the library they made as if the reader already knows everything about DMA inside and out.. from what I gather its useful enough and complex enough to warrant some kind of startup literature.

    I should mention I did try it with those shared pins you mentioned and it just stopps doing anything.. but I will try again as I have changed a few other things as well.. Ill report back shortly..

    I was also thinking of maybe just bit-banging the DAC.. The FastSPI_LED library had some interesting stuff to that effect but it looks like it is set up more specifically then their wordpress entry would lead me to believe:

    Code:
    #include "FastSPI_LED2.h"
    SPIOutput<11, 13, 10, 0> SPI;
    setup() { SPI.init(); }
    loop() { 
      // setup some data in a buffer
      SPI.writeBytes(pData, nBufferLen);
    }
    and

    Code:
    if(b & (1 << BIT)) {
    			Pin<DATA_PIN>::fastset(dataPort, dataHi);
    		} else { 
    			Pin<DATA_PIN>::fastset(dataPort, dataLo);
    		}
    		Pin<CLOCK_PIN>::fastset(clockPort, clockHi);
    		Pin<CLOCK_PIN>::fastset(clockPort, clockLo);

    and finally

    Code:
    if(b & (1 << BIT)) {
    			Pin<DATA_PIN>::fastset(dataPort, dataHiCLockHi);
    			Pin<DATA_PIN>::fastset(dataPort, dataHiCLockLo);
    		} else { 
    			Pin<DATA_PIN>::fastset(dataPort, dataLoCLockHi);
    			Pin<DATA_PIN>::fastset(dataPort, dataLoCLockHi);
    		}

    all referenced from this page :


    http://waitingforbigo.com/2013/02/19...pushing-needs/


    Thanks! I really do appreciate any input greatly

  5. #5
    Senior Member
    Join Date
    Feb 2013
    Posts
    563
    Quote Originally Posted by MacroMachines View Post
    I guess one of the things that is confusing to me is that if the DOUT/MOSI pin is sending SPI - DMA to OLED, then if I want to write out the word to the SPI DAC on the same pin, would there even be a performance gain? Isn't the point to be able to let the DMA do its thing through that pin while the micro controller does other stuff that doesn't touch that pin? Thus I was trying to figure out if I can use the greyed out secondary SPI pins on the reference card to write out to the DAC so that they can be as independent as possible.
    the greyed out pins are "ALT", not a second SPI port, so that won't work. I'd guess something DMA might still be doable, but you'll be talking to two peripheral devices, which will need a more elaborate scheme... but DMA isn't my forte either

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,675
    Neither your code nor Adafruit's library seem to be use SPI transactions. So both are sharing the same settings.

    Maybe you could use a lower speed and otherwise the same settings as Adafruit's library?

    The (much harder but much better) alternative would be the edit the library to add SPI.beginTransaction() and SPI.endTransaction() around each of these SPI usages, and of course the same in your code.

  7. #7
    Senior Member
    Join Date
    Feb 2013
    Posts
    563
    Quote Originally Posted by MacroMachines View Post
    I am currently trying to speed up communication on my project by using DMA
    on a different note, so are you concerned about the DAC sampling rate/jitter/etc, or the display refresh rate, or both?

    assuming a/the module's performance is mostly dictated by the performance of the DAC and the display is more, well, eye-candy, did you consider using the i2c version of said adafruit OLED display? or bitbang/use software SPI for the display? or wait for the teensy 3++, which will have more than one SPI, i gather. or, if you can't wait, use a stm32f10x, or stm32F4xx?

  8. #8
    Senior Member
    Join Date
    Dec 2014
    Posts
    134
    Quote Originally Posted by PaulStoffregen View Post
    Neither your code nor Adafruit's library seem to be use SPI transactions. So both are sharing the same settings.

    Maybe you could use a lower speed and otherwise the same settings as Adafruit's library?

    The (much harder but much better) alternative would be the edit the library to add SPI.beginTransaction() and SPI.endTransaction() around each of these SPI usages, and of course the same in your code.

    I am not sure what you are referring to as not having the beginTransaction, the libraries I am using for the OLED and graphics are a significant mod to the Adafruit library by sumotoy here:
    https://github.com/sumotoy/Adafruit-GFX-Library
    https://github.com/sumotoy/OLED_SSD1306

    So what is the difference between SPI transaction and SPI transfer?

  9. #9
    Senior Member
    Join Date
    Dec 2014
    Posts
    134
    Quote Originally Posted by mxxx View Post
    on a different note, so are you concerned about the DAC sampling rate/jitter/etc, or the display refresh rate, or both?

    assuming a/the module's performance is mostly dictated by the performance of the DAC and the display is more, well, eye-candy, did you consider using the i2c version of said adafruit OLED display? or bitbang/use software SPI for the display? or wait for the teensy 3++, which will have more than one SPI, i gather. or, if you can't wait, use a stm32f10x, or stm32F4xx?
    I tried the i2c version (same version as I have now but you just connect some jumper pads on the back to switch between i2c and spi). With i2c the display runs so slow that my dac writes and the core waveform generation code get slowed way down. IE: the screen writes take longer each one and thus it hangs each time for everything else.

    As far as jitter and refresh rate, both are irrelevant to me on this as long as it doesn't hang. I am actually trying out a new core built around intervalTImer interrupts and priorities. My current test is here:

    Code:
    #include <SPI.h>
    #include <Adafruit_GFX2.h>
    #include <OLED_SSD1306.h>
    #include <elapsedMillis.h>
    
    #define DAC_CS 15 
    #define OLED_DC     9
    #define OLED_CS     10
    #define OLED_RESET  14
    OLED_SSD1306 display(OLED_CS, OLED_DC, OLED_RESET);
    
    
    
    IntervalTimer DACtimer;
    byte totalWaves = 4;
    word wave[4][2];
    word wavePhase = 0;
    
    void setup()   {                
      display.begin();
      display.setBitrate(24000000);
      pinMode(DAC_CS, OUTPUT);
      digitalWrite(DAC_CS, HIGH);
      SPI.setBitOrder(MSBFIRST);
      DACtimer.begin(DACoutSPI, 20);
      //OLEDtimer.begin(OLEDout, 33333);
    }
    
    
    void loop(){
        DACoutSPI(); 
        display.drawLine(random(128), random(64), random(128), random(64), WHITE);
        display.display();
        display.clearDisplay();
    }
    
    
    void DACoutSPI(){     //SPI DAC write
      for(byte channel = 0; channel < totalWaves; channel++){
        wave[channel][wavePhase] = random(4096);
        digitalWrite(DAC_CS, LOW);
        byte formatDacMSB = (channel<<6 | B00010000 | ((highByte(wave[channel][wavePhase])) & B00001111));
        byte formatDacLSB = (lowByte(wave[channel][wavePhase]));
        SPI.transfer(formatDacMSB);
        SPI.transfer(formatDacLSB);
        digitalWrite(DAC_CS,HIGH);
      }
    }

  10. #10
    Senior Member
    Join Date
    Feb 2013
    Posts
    563
    Quote Originally Posted by MacroMachines View Post
    I tried the i2c version (same version as I have now but you just connect some jumper pads on the back to switch between i2c and spi). With i2c the display runs so slow that my dac writes and the core waveform generation code get slowed way down. IE: the screen writes take longer each one and thus it hangs each time for everything else.
    i see. depending on how slow, i guess getting to work DMA for the DAC (https://github.com/crteensy/DmaSpi ?) might help in that case, in as much you'd presumably free up some cpu time the thing can spend talking to the display.

    but as long as the PIT thing + priorities works ... i'm using u8glib myself and have no need for kHz sampling rates in this case so i never really looked into sharing the SPI bus efficiently/effectively. i must admit i don't quite get the test code though. why are you calling DACoutSPI in loop()? wouldn't that be your ISR? presumably you could speed it up by using SPIFIFO.


    edit. as for transactions, see Paul's write up here: http://dorkbotpdx.org/blog/paul/spi_...ons_in_arduino

    and info dispersed over the forum.
    Last edited by mxxx; 06-01-2015 at 06:54 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •