STM32 DAC for resolver excitation

Post Reply
User avatar
johu
Site Admin
Posts: 5769
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1011 times
Contact:

STM32 DAC for resolver excitation

Post by johu »

I found a sudden urge to experiment with the DAC. I have here an STM32F107VCT6.
Just sort of "blogging" about it here.

Starting out simple with software triggering. First had to upgrade libopencm3 because the forked version didn't have DAC functions.
setup:

Code: Select all

   rcc_periph_clock_enable(RCC_DAC); //CAN
   dac_enable(DAC1, DAC_CHANNEL1);
   dac_set_trigger_source(DAC1, DAC_CR_TSEL1_SW);
   gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO5);
In cyclic 10 ms task:

Code: Select all

   seq1Ctr = (seq1Ctr + 1) & 0x3;

   dac_load_data_buffer_single(DAC1, seq1Ctr << 10, DAC_ALIGN_RIGHT12, DAC_CHANNEL1);
   dac_software_trigger(DAC1, DAC_CHANNEL1);
seq1Ctr is a 0-3 counter.

result:
Attachments
IMG_20210506_173831.jpg
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
johu
Site Admin
Posts: 5769
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1011 times
Contact:

Re: STM32 DAC

Post by johu »

Ok, that took slightly longer. Generating a 4.4 kHz sawtooth from DMA:
IMG_20210506_182355.jpg
We need more clocks:

Code: Select all

   rcc_periph_clock_enable(RCC_TIM5); //DAC timing
   rcc_periph_clock_enable(RCC_DMA2);  //DAC
   rcc_periph_clock_enable(RCC_DAC);
Now comes a lot of init. First the DAC

Code: Select all

   dac_enable(DAC1, DAC_CHANNEL1);
   dac_set_trigger_source(DAC1, DAC_CR_TSEL1_T5);
   dac_trigger_enable(DAC1, DAC_CHANNEL1);
   dac_dma_enable(DAC1, DAC_CHANNEL1);
   gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO5);
We set it to be triggered by Timer 5 and fed by DMA (DMA2, channel 3)

then the timer:

Code: Select all

   timer_set_prescaler(TIM5, 0);
   timer_set_period(TIM5, 63); //Wrap at 1.125 MHz
   timer_direction_up(TIM5);
   timer_enable_update_event(TIM5);
   timer_set_master_mode(TIM5, TIM_CR2_MMS_UPDATE);
   timer_generate_event(TIM5, TIM_EGR_UG);
   timer_enable_counter(TIM5);
So it wraps at 1.125 MHz thus loading a new value to the DAC at that rate.
Now we initialize our sawtooth data

Code: Select all

static uint8_t dacdata[256];

   for (int i = 0; i < sizeof(dacdata); i++)
      dacdata[i] = i;
Aha, so 256 values. 1.125 MHz / 256 is 4.394 kHz. Sounds familiar? Yes that is half the frequency at which our PWM interrupt fires. So after two interrupts we have run through a period. Just like the low-pass filtered exciter pin would do. See, where this is going?

Alright, finally some boring DMA setup:

Code: Select all

   dma_channel_reset(DMA2, DMA_CHANNEL3);
   dma_set_read_from_memory(DMA2, DMA_CHANNEL3);
   dma_set_memory_address(DMA2, DMA_CHANNEL3, (uint32_t)dacdata);
   dma_set_peripheral_address(DMA2, DMA_CHANNEL3, (uint32_t)&DAC_DHR8R1(DAC1));
   dma_set_peripheral_size(DMA2, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT);
   dma_set_memory_size(DMA2, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT);
   dma_enable_circular_mode(DMA2, DMA_CHANNEL3);
   dma_set_number_of_data(DMA2, DMA_CHANNEL3, sizeof(dacdata));
   dma_enable_memory_increment_mode(DMA2, DMA_CHANNEL3);
   dma_enable_channel(DMA2, DMA_CHANNEL3);
And we're rolling. All thats needed now to replicate the makeshift resolver excitation of the poorer equipped RBT6 is to replace the saw tooth by sine and to synchronize the phase with the PWM interrupt. Like using one shot timer mode or so.
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
johu
Site Admin
Posts: 5769
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 157 times
Been thanked: 1011 times
Contact:

Re: STM32 DAC

Post by johu »

We wanted sine, right? We have sine:
IMG_20210506_184208.jpg

Code: Select all

   for (int i = 0; i < sizeof(dacdata); i++)
      dacdata[i] = SineCore::Sine(i * 256) / 270 + 128;
We pull one full period from our SineCore module, divide it by 270 (not 256, because maxing out the DAC creates distortion) and add 128 because it's signed.

Whats all that for? viewtopic.php?p=27113#p27113
So I think we're looking into a new "encmode" called "ResolverDAC". Thats for later.
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
Jack Bauer
Posts: 3563
Joined: Wed Dec 12, 2018 5:24 pm
Location: Ireland
Has thanked: 1 time
Been thanked: 87 times
Contact:

Re: STM32 DAC

Post by Jack Bauer »

That's brilliant. Nice work Johannes:)
I'm going to need a hacksaw
User avatar
mjc506
Posts: 343
Joined: Wed Sep 09, 2020 9:36 pm
Location: Wales, United Kingdom
Has thanked: 30 times
Been thanked: 28 times

Re: STM32 DAC for resolver excitation

Post by mjc506 »

Looking good :-)
Post Reply