1

I am trying to write code to play simple songs using a STM32F407G discovery board and the STM32CUBEIDE. I created an array to store the note frequency values and also one for their duration(not 100% accurate yet,just wanted to test a concept). I managed to get the buzzer to play the tones using PWM, however it does not finish my song and stops after a few tones, but if I leave the board plugged in it restarts from the beginning after a few minutes.

I have tried changing the delay before,after or in between notes and also tried playing around with the frequencies and ARR value, but to no avail. If anyone could point me in the right direction or show me where I made an error I will be grateful.

I enabled PWM output on pin A0, using the internal clock at 16MHz with 0 prescaler value. I will attach some code below: inside my while(1) loop I have: playSong():

EDIT: Solved the problem, if you change the ARR value the CNT register must be cleared to zero after every 'note', otherwise the count value could be greater than the ARR value which then causes issues.

uint32_t Frequency = C;
uint32_t CLOCK = 16000000;
int i;

/*                       Hap  py  Birth Day  to  you,  Hap py   birth day  to
                         C4   C4   D4   C4   F4   E4   C4   C4   D4   C4   G4 */
unsigned int notes[] = { 262, 262, 294, 262, 349, 330, 262, 262, 294, 262, 392,

/*                       you, Hap py  Birth Day  dear  xxxx      Hap  py   birth
                         F4   C4   C4   C5   A4   F4   E4   D4   B4b  B4b  A4 */
                         349, 262, 262, 523, 440, 349, 330, 294, 466, 466, 440,

/*                       day  to  you
                         F4   G4   F4   */
                         349, 392, 349
                        };

unsigned int duration[] = {1,1,2,2,2,2,1,1,2,2,2,2,1,1,2,2,2,2,2,1,1,2,2,2,2};


void noTone(){
    htim2.Instance->CCR1=0;
    HAL_Delay(50);
}

void playSong(){

    for (i = 0; i <55; i++) {

    Frequency = CLOCK/notes[i];
    htim2.Instance->ARR=Frequency;
    htim2.Instance->CCR1=Frequency/2;
    HAL_Delay(400*duration[i]);
    noTone();

    }

    }




/* USER CODE END 0 */```

```/* USER CODE BEGIN WHILE */


  while (1)
  {

    playSong();


    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }```
  • 2
    `i <55` But neither `notes` nor `duration` arrays have `55` elements. – dxiv Aug 30 '20 at 07:51
  • I tried changing that value either larger or smaller to see if it fixed my issue, but it did not. I originally had it as i – Altus Cilliers Aug 30 '20 at 08:03
  • The hardware PWM generator probably works asynchron to the CPU. When you try to change the settings of the generator while out of sync, you going to crash the system, and it restarts. You better read the datasheet of your board. For example: 16000000 divided by 262 = 61068.7022901 but a clockrate can only be an integer number. The small difference of 0.7022901 adds in time, and CPU and PWM generator go out of sync. When you try to change the register settings, the system crashes. A cheap workaround would be to use notes which divide clockrate to an integer, like: 16000000 divided by 256 – paladin Aug 30 '20 at 09:58
  • @paladin I assumed that since I defined my Frequency variable as an int, it would get truncated to an integer and not a float, is this not the case? – Altus Cilliers Aug 30 '20 at 11:13
  • @AltusCilliers `i < sizeof(notes) / sizeof(notes[0])` gives you the count of the array, in this case `25`. – dxiv Aug 30 '20 at 16:10
  • @dxiv thanks, however I don't think this is the issue here as I have tried i< 25 and now your suggestion however it does not fix my issue – Altus Cilliers Aug 30 '20 at 18:11
  • 1
    @AltusCilliers It is *an* issue. Whenever `i >= 25` the code runs into [UB](https://en.cppreference.com/w/cpp/language/ub) so that's the first thing to fix before you look into what *other* issues might exist. – dxiv Aug 30 '20 at 18:14
  • @Altus Cilliers Please read the datasheet of your board, it explains it much more better, than anyone of us could do. Usually, when changing a asynchronous register, like that of your PWM generator, you have either to use hardware interrupts or you have to poll a register status flag all the time. Your program doesn't do anything of that. An example for a polling: `if(pwm_generator.statusbit.is_sync==1) {pwm_generator.statusbit.set_new_frequency=1;}` – paladin Aug 30 '20 at 21:13
  • @paladin I'll take a look at that thanks, I'm still new to using microcontrollers etc so the manual is quite hard to navigate if I don't exactly know what I am looking for, but I will go have a look and see what I can do. – Altus Cilliers Aug 31 '20 at 08:17

1 Answers1

0

Solved the problem, if you change the ARR value the CNT register must be cleared to zero after every 'note', otherwise the count value could be greater than the ARR value which then causes issues.