Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post your cool example code here.
User avatar
RogerClark
Posts: 7540
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by RogerClark » Sun Nov 26, 2017 11:22 pm

I am not sure if this would speed things up very much , but

Code: Select all

  phaseAccumulator1++;       // Move to next samples position
  phaseAccumulator2++;

  if (phaseAccumulator1 >= maxSamples1) phaseAccumulator1 = 0;          // Check for overflow i.e. value of 1024 at max freq
  if (phaseAccumulator2 >= maxSamples2) phaseAccumulator2 = 0;
could be changed to


Code: Select all

  if (++phaseAccumulator1 >= maxSamples1) phaseAccumulator1 = 0;          // Check for overflow i.e. value of 1024 at max freq
  if (++phaseAccumulator2 >= maxSamples2) phaseAccumulator2 = 0;

Do speed up the calls to analogRead, you'd need to store the ADC device, as the core has this function

Code: Select all

uint16 analogRead(uint8 pin) {
    adc_dev *dev = PIN_MAP[pin].adc_device;
    if (dev == NULL) {
        return 0;
    }

    return adc_read(dev, PIN_MAP[pin].adc_channel);
}
i.e add devices for PA2,PA4 and PA6

Code: Select all

adc_dev *adcDevPA2= PIN_MAP[PA2].adc_device;
adc_dev *adcDevPA4= PIN_MAP[PA4].adc_device;
adc_dev *adcDevPA6= PIN_MAP[PA6].adc_device;
and also store the ADC channel

Code: Select all

int adcChannelPA2= PIN_MAP[PA2].adc_channel;
int  adcChannelPA4= PIN_MAP[PA4].adc_channel;
int  adcChannelPA6= PIN_MAP[PA6].adc_channel;
then call

Code: Select all

 adc_read(adcDevPA2, adcChannelPA2);
Note. I've not test compiled this code so there may be mistakes, but you get the idea

User avatar
KenLaszlo
Posts: 18
Joined: Sun Oct 29, 2017 3:28 pm

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by KenLaszlo » Mon Nov 27, 2017 10:24 am

Hey Roger

Thanks for the additions - Yes, I understand.
I'm coming from an AVR background, so not fully conversant with how these new 32 bit devices run.

Bizarrely, I noticed that grabbing a 16-bit sample from the wavetable in flash memory (Sine for example) was a fraction slower than doing one or two 32-bit maths functions to generate the waveform (as in Saw and Reverse Saw) - This was surprising. There was only a fraction of speed increase in it (like going from 440Hz to 450Hz on a free-running oscillator in the main loop, not using interrupts), but a speed increase none-the-less.
There was a similar tiny increase changing 'Switch/Case' to 'If/Thens/Else' in the section for calculation of the waveforms.

Ken

User avatar
RogerClark
Posts: 7540
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by RogerClark » Mon Nov 27, 2017 7:29 pm

Access to flash is not at the full clock speed of the processor. I think there are either 2 or 1 “wait states” for each read.

Try removing the PROGMEM stuff and remove the const declaration on one of the wave tables and it should get put in RAM which will be much faster

User avatar
KenLaszlo
Posts: 18
Joined: Sun Oct 29, 2017 3:28 pm

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by KenLaszlo » Tue Nov 28, 2017 11:23 am

Thanks, yes. I can confirm that getting the table out of flash memory does make it a fraction faster. Not dramatically so, but a definite increase.
In a timed loop, the time taken reduced from 3.20 microseconds to 3.14 microseconds.

I recently experimented with overclocking the chip to 128Mhz and changed the (SPI_CLOCK_DIV4) to (SPI_CLOCK_DIV8) to ensure that the PT8211 was running within it's limits . . . and it all worked fine.
A test of a frequency generating loop had the frequency increase from 630Hz to over 1.1Khz just by this overclocking.
I was worried that there might be errors reading the Pots at this unguaranteed rate (ADC), but they seemed fine as well.

I'm pretty sure that the main time-hog (perhaps unavoidable) is taken by the SPI.write command which, by my calculations is taking 1.3 microseconds alone to complete.

I'm looking at getting as much speed as I can right now for one of my future goals would be to use the chip for the full range of audio frequencies with multiple waveform selection . . . right now, that's looking quite a tall order.

Ken

stevestrong
Posts: 1937
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by stevestrong » Tue Nov 28, 2017 1:02 pm

An SPI.write command will last aprox. the time needed to transfer the data bits with SPI frequency.
So if you set the SPI frequency to 36MHz, then writing one byte should take ~0,3 µseconds.
Lower SPI clock frequency will increase the time accordingly.

User avatar
KenLaszlo
Posts: 18
Joined: Sun Oct 29, 2017 3:28 pm

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by KenLaszlo » Tue Nov 28, 2017 1:40 pm

Thanks, Steve.

The PT8211 has a maximum rated clock frequency of 20Mhz . . .. however . . . my thinking was the same as yours ;) .
I changed the clock rate division for 72 / 2 (36Mhz) and it still seems to run fine.
Looks like the PT8211 (well, my chip at least) can be overclocked.
Further testing to be done for stability.

Ken

User avatar
RogerClark
Posts: 7540
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by RogerClark » Tue Nov 28, 2017 8:49 pm

Calling spiWrite for single bytes is not very efficient, there is a lot of overhead checking if the SPI ready to accept data

You could try bypassing these checks and just directly write to the SPI output register

victor_pv
Posts: 1788
Joined: Mon Apr 27, 2015 12:12 pm

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by victor_pv » Tue Nov 28, 2017 10:40 pm

If you want to speed things up, you should look at using DMA.
Then the CPU can do something, like process or fill a buffer while the DMA sends another one on it's own to the SPI peripheral.
So the CPU doesn't have to sit idle waiting for the SPI transfer.

Some of these MCUs have i2s mode, and in that mode the SPI peripheral can generate the WS signal on it's own. That's not the case on the bluepill, but you should be able to use a timer to achieve the same.
Configure a timer to overflow at the frequency you need. Set one channel output to flip on CC match, and set the value to half the timer overflow, so there will be 1 match even per timer overflow.
Then configure the DMA channel to which that timer channel is connected (check reference manual), to do the DMA requests for the SPI peripheral. Enable DMA requests in the timer channel (not the SPI peripheral, since when to do transfers will be decided by the timer, not the SPI peripheral).
Then build your table of samples in the RAM, and fire the timer.
Each time the timer CC matches the timer count, the WS output (timer channel output) will switch to the opposed value (0 pr 1), and a new DMA request will be generated/ The DMA peripheral will load a sample from ram, load it to SPI DR register, and the SPI will send it out.
On the next CC match, the WS output will switch again, for the other channel, and the DMA will pick a new sample, and load it to DR, which will send it out.

If I have time I'll try to write you some code later.

User avatar
RogerClark
Posts: 7540
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by RogerClark » Tue Nov 28, 2017 11:24 pm

Victor.

I had the same thought

Just setup the DMA with the wavetable buffer and configure a timer to generate interrupts to trigger the DMA at the appropriate speed.

But, I wasnt sure if it was possible or how to configure it.

User avatar
KenLaszlo
Posts: 18
Joined: Sun Oct 29, 2017 3:28 pm

Re: Dual LFO with choice of waveforms using PT8211 and Blue Pill

Post by KenLaszlo » Wed Nov 29, 2017 11:20 pm

Thanks.

I'm just hacking spi.h now.

spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)

I'm looking with interest at spi.dmaSend and your spi.dmaSendAsync that you developed for use with your Neopixels.
Would I need any special consideration to use those commands, please?
Even just using a none blocking DMA send for a single 16 bit of data would be useful for me.
Pehaps these commands might be a better option as I am envisaging timing issues with writing directly to the register and not checking if the data has finished being sent or that SPI is ready before going round again for another send.

At the moment, my code works on a sample-by-sample basis, with each sample calculated from the state of various things . . . sending a large block of 'predefined' samples to be transferred using DMA might not be possible for my project in its current form.

Ken
Last edited by KenLaszlo on Wed Nov 29, 2017 11:37 pm, edited 2 times in total.

Post Reply