My goal is to use this setup as a 2 channel oscilloscope with 2 channel signal generator.
I have display working perfectly fine.
The 2 analog input channels should use one ADC each to allow full 1MSPS sampling of 2 channels. (output channels should follow the same paradigm)
ADC/DAC access should be double buffered through DMA.
My problem is I have now idea what is wrong, my math says I'm only getting ~60kSPS. (if my math is wrong please let me know how to calculate it properly)
I've spent the last 18 hours digging all over the internet and have read every post here on Adafruit to no avail.
Code: Select all
/*
* developed from Adafruit 'Boing' ball demo for PyPortal
*/
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define SCREENWIDTH ILI9341_TFTHEIGHT
#define SCREENHEIGHT ILI9341_TFTWIDTH
// pins
#define TFT_D0 37 // data bit 0 (MUST be on PORT byte boundary)
#define TFT_WR 4 // write strobe
#define TFT_DC 3 // command/data
#define TFT_CS 2 // chip select
#define TFT_RST 6 // reset
#define TFT_RD 5 // read strobe
#define TFT_BACKLIGHT 7
// ILI9341 with 8-bit parallel interface:
Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD);
// for FPS counting (sstimate)
uint32_t startTime, frame = 0;
void setup() {
Serial.begin(115200);
//while (!Serial);
// TODO make pwm for dimmable backlight
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
tft.begin();
tft.setRotation(3);
// tft.drawBitmap(0, 0, (uint8_t *)background, SCREENWIDTH, SCREENHEIGH, GRIDCOLOR, BGCOLOR);
tft.fillScreen(ILI9341_BLACK);
// setup and start adc/dma
initADC(A2, ADC0);
initDMA();
ADC0->SWTRIG.bit.START = 1;
// initial time
startTime = millis();
}
// adc dma buffers and flags
uint16_t adc0Buff[2][2048];
bool adc0Active = true; // false = buffer 0, true = buffer 1
bool adc0Valid = false;
volatile uint64_t lastTime = 0;
uint16_t col = 0;
void loop() {
// other logic here
// wait for last frame complete
tft.dmaWait();
tft.endWrite();
tft.startWrite();
if (adc0Valid)
{
uint16_t rendBuff[2][240];
uint8_t rendBuffActive = 0;
for (uint16_t x=0; x<320; x++)
{ // loop columns
tft.setAddrWindow(x, 0, 1, 240);
// calculate where to draw waveform pixel
// 2^12=4096 (need to map to {0:239})(each pixel corresponds to 68.266... adc values)
uint16_t value = map(adc0Buff[adc0Active][x], 0, 4096, 0, 239);
// Serial.print(adc0Buff[adc0Active][x]);
// Serial.print(" : ");
// Serial.println(value);
for (uint16_t y=0; y<240; y++)
{ // loop rows
if (y == value) {
// draw waveform pixel
rendBuff[rendBuffActive][y] = ILI9341_YELLOW;
} else {
// draw background
rendBuff[rendBuffActive][y] = ILI9341_BLACK;
}
}
tft.dmaWait();
tft.writePixels(&rendBuff[rendBuffActive][0], 240, false);
rendBuffActive = 1 - rendBuffActive;
}
adc0Valid = false;
uint64_t thisTime = micros();
Serial.println((uint32_t)(thisTime-lastTime)/2048); // per-sample time (prints 24)
lastTime=thisTime;
}
// else Serial.println("invalid buffer");
// FPS estimate
// if ( !(++frame & 255)) { // Every 256 frames...
// uint32_t elapsed = (millis() - startTime) / 1000; // Seconds
// if (elapsed) {
// Serial.print(frame / elapsed);
// Serial.println(" fps");
// }
// }
}
#include <wiring_private.h>
void initADC(int pin, Adc *ADCx)
{
ADCx->CTRLA.bit.ENABLE = 0x00;
while (ADCx->SYNCBUSY.bit.ENABLE);
pinPeripheral(pin, PIO_ANALOG);
ADCx->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND;
while (ADCx->SYNCBUSY.bit.INPUTCTRL);
ADCx->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber;
while (ADCx->SYNCBUSY.bit.INPUTCTRL);
ADCx->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV4_Val;
// ADCx->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV8_Val;
// ADCx->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV2_Val;
while (ADCx->SYNCBUSY.bit.CTRLB);
ADCx->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
while (ADCx->SYNCBUSY.bit.CTRLB);
ADCx->SAMPCTRL.reg = 0x0;
while (ADCx->SYNCBUSY.bit.SAMPCTRL);
ADCx->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | ADC_AVGCTRL_ADJRES(0x0ul);
while (ADCx->SYNCBUSY.bit.AVGCTRL);
ADCx->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val;
while (ADCx->SYNCBUSY.bit.REFCTRL);
ADCx->CTRLB.bit.FREERUN = 1;
while (ADCx->SYNCBUSY.bit.CTRLB);
ADCx->CTRLA.bit.ENABLE = 0x01;
while (ADCx->SYNCBUSY.bit.ENABLE);
}
void adc0Complete(Adafruit_ZeroDMA *dma)
{
// flag which buffer is valid
adc0Active = !adc0Active;
adc0Valid = true;
}
Adafruit_ZeroDMA adc0DMA;
void initDMA()
{
adc0DMA.allocate();
auto desc = adc0DMA.addDescriptor((void*)(&ADC0->RESULT.reg), adc0Buff[0], 2048, DMA_BEAT_SIZE_HWORD, false, true);
desc->BANNED.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
desc = adc0DMA.addDescriptor((void*)(&ADC0->RESULT.reg), adc0Buff[1], 2048, DMA_BEAT_SIZE_HWORD, false, true);
desc->BANNED.bit.BLOCKACT = DMA_BLOCK_ACTION_INT;
adc0DMA.loop(true);
adc0DMA.setTrigger(0x44);
adc0DMA.setAction(DMA_TRIGGER_ACTON_BEAT);
adc0DMA.setCallback(adc0Complete);
adc0DMA.startJob();
}
I know a lot of my buffer is not being rendered.