For a project I'm working on I'll need to output data at almost exactly 4.3MHz and 8.6MHz from one digital pin. Right now I'm using DMA transfers to the SPI peripheral, but I've noticed that no matter what SPISettings I pass in for SPI.beginTransaction, my oscilloscope measures that the SCK pin only ever outputs multiples of 1MHz. This might cut it for the 4.3Mb/s speed, but definitely not for 8.6Mb/s.
I should note that although I'm using the SPI peripheral right now, I'm only actually using the MOSI pin and leaving SCK unconnected since the target device has its own clock recovery mechanism.
(Okay, that's not totally honest. I noticed that MOSI goes high between SCK pulses after each byte for some reason, so in reality I'm using a CMOS AND gate to filter that out and I'm actually trying to use SCK&MOSI as my output. that's not totally relevant though, I think.)
I'm using the Teensy 3.6 right now (for the clock speed and convenient SD card access) but I wouldn't object to using a different micro controller as long as I can still use DMA for the data output. I figured I could probably try replacing the crystal with something slightly off in order to make the difference, but I feel like that's abusing the hardware. What alternatives are there?
I doubt the source code would help much, but here's what I've got right now:
I should note that although I'm using the SPI peripheral right now, I'm only actually using the MOSI pin and leaving SCK unconnected since the target device has its own clock recovery mechanism.
(Okay, that's not totally honest. I noticed that MOSI goes high between SCK pulses after each byte for some reason, so in reality I'm using a CMOS AND gate to filter that out and I'm actually trying to use SCK&MOSI as my output. that's not totally relevant though, I think.)
I'm using the Teensy 3.6 right now (for the clock speed and convenient SD card access) but I wouldn't object to using a different micro controller as long as I can still use DMA for the data output. I figured I could probably try replacing the crystal with something slightly off in order to make the difference, but I feel like that's abusing the hardware. What alternatives are there?
I doubt the source code would help much, but here's what I've got right now:
Code:
#include <Arduino.h>
#include "DMAChannel.h"
#include <spi.h>
#include <SdFs.h>
//SD CARD CARGO CODE=========================================================
#define SD_FAT_TYPE 3
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
#define SD_CONFIG SdioConfig(FIFO_SDIO)
SdFs sd;
FsFile file;
//===========================================================================
DMAChannel dmachannel;
uint32_t data[256];
void dmaFinishedTest() {
digitalWrite(33,HIGH);
}
void dmaSpiTest() {
for (uint16_t i = 0; i < 256; i++) {
data[i] = 0b10101010;
}
// Setup the SPI clocks and pin configurations
SPI.begin();
SPI.beginTransaction(SPISettings(4300000, MSBFIRST, SPI_MODE0)); //this gives me a real output speed of 5Mb/s for some reason
// Setup SPI for DMA transfer
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
dmachannel.sourceBuffer(data, 256); // The data for which we wish to transmit and its length
dmachannel.destination((volatile uint8_t&)SPI0_PUSHR); // Move data into the SPI FIFO register
dmachannel.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); // Only transfer data once the previous byte has been transmited (This is to ensure all bytes are sent)
dmachannel.disableOnCompletion(); // Stop after transmitting all 256 bytes
// dmachannel.interruptAtCompletion();
dmachannel.attachInterrupt(dmaFinishedTest);
pinMode(33,OUTPUT);
dmachannel.enable(); // Begin transmit
}
/** Wait for and consume a keypress over USB **/
void waitForKeyPress()
{
Serial.println("\nPress a key to continue\n");
while(!Serial.available());
while(Serial.available())
{
Serial.read();
}
}
void sdCardTest() {
if (!sd.begin(SD_CONFIG)) {
Serial.println(F("sd card?"));
while(true);
}
if (!file.open("test", FILE_READ)) {
Serial.println(F("file?"));
while(true);
}
#define BUF_SIZE 512
uint8_t buf[BUF_SIZE/8];
Serial.println(F("Reading..."));
for (int i = 0; i < 5; i++) {
file.read(buf,8);
}
uint64_t filesize = file.size();
for (uint64_t i = 0; i < filesize; i++) {
Serial.print("value="); Serial.println(buf[i],HEX);
}
}
void setup() {
Serial.begin(9600);
waitForKeyPress();
sdCardTest();
dmaSpiTest();
}
void loop() {
}