Hello, I am trying to use the SPI clock to generate a clock signal to a microphone. The clock must be between 1-3 MHz so I have created the following code:
void setup() {
// Put initialization like pinMode and begin functions here.
SPI.setClockSpeed(3, MHZ);
SPI.begin();
delay(5000);
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
SPI.transfer(0xffff);
}
the problem is, when I connect an oscilloscope it show that the clock is always at 1, and only have slight peaks at 0.
First, if you are using default AUTOMATIC system mode, loop() will only run aproximately every 1ms, since all the cloud tasks take place between iterations of loop() taking that long.
Next, I’d not abuse SPI for that, since the clock won’t have a 50% duty cycle.
You could use a timed interrupt for that via SparkIntervalTimer library.
Or you might consider using a PWM, but I haven’t checked the max. rate for that.
With a resolution set to 2 bit you may get the max frequency, but depending on pin that might be more or less.
And after rethinking your 1~3MHz SparkIntervalTimer will be out too, due to it's max rate of 3~5µs between each trigger.
So you might be back at SPI
Try SYSTEM_THREAD(ENABLED) to decouple the cloud thread from loop() and go for longer running DMA based SPI.transfer() with a calkback retriggering the next transfer.
But the more professional solution would be to use a 3MHz quarz oszillator.
But the non-symmetric duty cycle will still be an issue.
To overcome that you could go for 6MHz and use an external flip-flop.
Having said this, @rickkas7 or @peekay123 may have some more fitting suggestions since they have already been tapping into to hardware timers of the µC and provide a less hacky solution.
Actually, I recommend using an external oscillator to get the correct frequency and duty cycle. As @ScruffR has it, the ISR call will be recursive and may cause a stack overflow. If not, it will cause a delay before and after each 128 byte block due to the interrupt latency and the DMA setup times. The resulting clock will be inconsistent.
@peekay123, I dare to contradict.
SPI.transfer(void*, void*, count, callback ) is an async function. It will start the DMA transfer an leave the function before the next callback call happens
But the non-consistent timing may be an issue, depending on the actual needs of the microphone used.
It seems like it ought to be possible, but I’m not really sure. I’m traveling right now and while I have a lot of things with me, I didn’t bring an oscilloscope or a logic analyzer LOL. I’ll try to look into this next week if an answer isn’t found before then.
I was able to do it with a hardware timer in PWM mode using the STM32F205 bare metal. I’m not positive this is a great idea, but it does appear to work. I got a nice 2.857 MHz signal output on D3.
I tried the below without any luck GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_TIM3);
My overall goal is to increase the SPI clock frequency to ~5MHz-6MHz as I connected up an MCP3008 ADC that I would like to slightly overclock. Is that possible using an external clock?
I’m pretty sure that SPI cannot be externally clocked. The SPI clock can only be set to the STM32 peripheral clock divided by 2, 4, 8, 16, 32, 64, 128 or 256.
The peripheral clock is 60 MHz for SPI and 30 MHz for SPI1, I believe.