shredability
Member
Teensy 3.6, So the deal is I'm using a DAC where the data format should like like this (below), This is just from polling the the spi bus the old fashioned way.
Meaning I need to do...
Is there a "simple" way to do this with the SPI/DMA library? This is what I have so far... ( Please note spi_cb is being called by an interval timer at a set cadence, when I want this 12byte sequence above to happen.
It gets me something like this...
So the dma is interrupting when it's transmission is finished, which isn't really what I want, I want an interrupt when the SPI is done three transmissions. If doing this with DMA isn't possible, it might even work if I just interrupt every SPI byte transmission, and then deal with the CS/timing every byte.
Meaning I need to do...
- Set CS low
- 3bytes DMA transaction
- Interrupt
- Set CS high
- GOTO step 1
Is there a "simple" way to do this with the SPI/DMA library? This is what I have so far... ( Please note spi_cb is being called by an interval timer at a set cadence, when I want this 12byte sequence above to happen.
Code:
#include "scan.h"
#include "SPI.h"
#include "ADC.h"
extern scan* pscan; // Pointer to the scan object
#define SS 9 // Slave select pin
/* Timer ISR, this is tiggeer at a set frequency to update the DACs*/
void tim_isr(void){
pscan->update();
}
/* This is a free running timer that triggers the ADC */
void pdb_isr(void) {
PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
}
/* This is triggered when one SPI DMA transfer is done*/
void dma_isr(void){
pscan->spi_cb();
}
scan::scan(scan** scanp, int interval)
:DACdataSize(3), interval(interval), points(250), LPerPoint(1/points), pointnum(0), spiPos(0)
{
*scanp = this;
float dt = float(interval) / 1e6;
dac0 = new waveform(1 , dt);
dac1 = new waveform(60, dt);
dac2 = new waveform(10, dt);
dac3 = new waveform(10, dt);
spiData = new uint8_t[DACdataSize]();
pinMode(SS, OUTPUT); // sets the digital pin 13 as output
SPI.begin(); //SS(9), MOSI(11), MISO(12), SCK(13)
SPI0_SR = 0xFF0F0000;
SPI0_RSER = 0x00;
SPI0_RSER = SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; // Make sure SPI triggers a DMA transfer after each transmit
// SPI.usingInterrupts(SPI0);
// SPI.attachInterrupt((void*)&spi_isr);
dmachannel.sourceBuffer(spiData, DACdataSize); // The data for which we wish to transmit and it's length
dmachannel.destination((volatile uint8_t&)SPI0_PUSHR); // Move data into the SPI FIFO register
dmachannel.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); // Only transfer once the previous byte has been transmited
dmachannel.disableOnCompletion();
dmachannel.interruptAtCompletion();
dmachannel.attachInterrupt((void*)&dma_isr);
/* ADC Config Below */
pinMode(A8, INPUT);
adc.setResolution(8);
adc.setAveraging(1, ADC_0); // set number of averages
adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_0); // LOW_SPEED adds +16 ADCK
adc.setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
adc.adc0->stopPDB();
pinMode(2, OUTPUT); // sets the digital pin 13 as output
digitalWrite(SS, true);
}
scan::spi_cb()
{
static uint16_t num(0);
digitalWrite(SS, true);
switch(spiPos)
{
case 0:
spiData[0] = 0b00011000;
num = 0xffff * dac0->pos;
break;
case 1:
spiData[0] = 0b00011001;
num = 0xffff * dac1->pos;
break;
case 2:
spiData[0] = 0b00011010;
num = 0xffff * dac2->pos;
break;
case 3:
spiData[0] = 0b00011011;
num = 0xffff * dac3->pos;
break;
case 4: // We done
SPI.endTransaction();
return;
}
spiData[1] = num & 0xFF; // Upper nibble
spiData[2] = num >> 8; // Lower nibble
spiPos++;
digitalWrite(SS, false);
dmachannel.enable(); // Begin transmit
}
It gets me something like this...
So the dma is interrupting when it's transmission is finished, which isn't really what I want, I want an interrupt when the SPI is done three transmissions. If doing this with DMA isn't possible, it might even work if I just interrupt every SPI byte transmission, and then deal with the CS/timing every byte.