Riprodurre audio e musica con STM32 - PCM con la PWM
La PCM (Pulse Code Modulation) è una tecnica di codifica digitale utilizzata per rappresentare segnali analogici (come l'audio) sotto forma di dati digitali. È uno dei metodi più comuni per digitalizzare segnali continui e viene utilizzata in molte applicazioni, come telecomunicazioni, registrazione audio digitale e trasmissione multimediale. Può essere definita come una soluzione primordiale per trasmettere audio tramite un microcontrollore.
Il primo step da seguire è quello di convertire un file .wav in un array (vettore) di valori esadecimali in linguaggio c. Il file .wav deve rispettare i seguenti parametri: avere canale audio mono, essere codificato in unsigned 8 bit PCM e avere una frequenza di campionamento tra gli 8 kHz e 16 kHz.
La frequenza di campionamento sarà una scelta a seconda dell’applicazione. Se la qualità dell’audio non interessa particolarmente, 8 kHz possono essere sufficienti. Ovviamente, a parità di bit di codifica, aumentando la frequenza di campionamento, aumenta anche lo spazio occupato in memoria.
Per lo sviluppo di questo progetto, oltre al software STM32CubeIDE, sarà necessario anche Audacity, per l’esportazione del formato audio .wav, e un piccolo programma che converta il file .wav in array PCM.
Esportazione e conversione del file audio
| Figura 1: pulsante per esportazione sul computer. |
- Formato: WAV (Microsoft);
- Canali: Mono;
- Frequenza di: 16000 Hz;
- Codifica: Unsigned 8-bit PCM.
| Figura 2: esportazione del progetto audio. |
| Figura 4: esecuzione del software wavc_converter.exe. |
Dopo aver cliccato Enter, usciranno alcune stringhe di descrizione del file audio. Alla fine, premere di nuovo Enter. Figura 5.
| Figura 5: conversione del file audio in array .c effettuata. |
All'interno della cartella contenente il programma, è ora presente un file .c contenente l'array di valori PCM. Il file .c avrà lo stesso nome del file .wav . Nel caso attuale, audio.c . Osservare la figura 6.
| Figura 6: file .c contenente l'array di valori PCM. |
| Figura 7: array contenuto nel file .c |
Scrittura del firmware
- All'interno dell'interfaccia .ioc, entrare nella sezione Pinout & Configurations -> Timers -> RTC e selezionare la spunta Activate Clock Source, come mostrato in figura 8.
Figura 8: attivazione dell' RTC. - Attivare un qualsiasi timer in modalità PWM. Per semplicità, si è scelto il TIM1, con i seguenti parametri: Clock source = Internal Clock, Channel 1 = PWM Generation CH1, Prescaler = 0, Counter Period = 1000 e, infine, Pulse = 500. Osservare la figura 9.
Figura 9: configurazione del TIM1 in modalità PWM. - Sarà necessario, ai nostri scopi, un timer delay che abbia periodo pari a 1 microsecondo (1 us). Attivare il timer TIM2 con i seguenti parametri: Clock Source = Internal Clock e Prescaler = 84-1. Osservare la figura 10. Per la scelta del prescaler, fare attenzione al datasheet del microcontrollore. La scheda NUCLEO F401RE ha il timer TIM2 situato sul BUS APB1, che ha una frequenza di 84 MHz.
Figura 10: impostazioni del timer TIM2.
| Figura 11: icona ingranaggio giallo |
Dopo la generazione del codice, ci si troverà all'interno della pagina di codice main.c
La prima azione da eseguire è la scrittura della funzione delay che sostituirà la già presente HAL_Delay, che ha il difetto di essere bloccante per il sistema.
Dichiarare nella sezione Private Macros, USER CODE BEGIN PM la funzione void delay(int); come mostrato in figura 12.
| Figura 12: dichiarazione della funzione delay. |
Scendere fino alla sezione USER CODE BEGIN 4 e dichiarare quindi il corpo della funzione delay, come in figura 13.
__HAL_TIM_SET_COUNTER(&htim2, 0);
while(__HAL_TIM_GET_COUNTER(&htim2) < us){
__NOP();
}
}
Per semplicità, si può copiare e importare l’array all’interno del file main.c, nella sezione di codice USER CODE BEGIN PV, come mostrato in figura 14.
| Figura 14: importazione dell'array. |
In seguito alla trascrizione dell'array PCM, è necessario definirne la dimensione, tramite una funzione associata e la primitiva sizeof(...) del linguaggio C. Osservare la figura 15.
| Figura 15: calcolo della dimensione dell'array. |
Il lettore avrà notato che la dimensione è un uint32_t e non un uint8_t, come definito per l'array.
Avendo a disposizione 8 bit, il valore massimo che può raggiungere il CCR è pari a 0xFF, ossia 255. Questo significa che il Duty Cycle è pari a 1 quando ARR = CCR. Da questo calcolo, si imposta ARR = 255.
Nella sezione USER CODE BEGIN PM dichiarare la funzione void PlayWave (uint8_t*, uint32_t), la quale avrà il compito di generare l'onda PWM per la riproduzione dell'audio (figura 16).
| Figura 16: dichiarazione della funzione PlayWave. |
L'array di valori PCM, l'audio, è passato per riferimento!
| Figura 17: corpo della funzione PlayWave. |
Codice ricopiabile:
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
__HAL_TIM_SET_AUTORELOAD(&htim1, 255);
for (uint32_t i = 0; i < length; i++) {
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, audio_data[i]);
delay(63);
}
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
}
| Figura 18: ciclo principale del programma. |
Il progetto si conclude caricando il firmware nella memoria del microcontrollore. Il risultato sarà la riproduzione dell'audio. Per l'esecuzione, si suggerisce di utilizzare un buzzer o un piccolo altoparlante, che sarà connesso al pin associato al timer TIM_CHANNEL_1.
.png)
Commenti
Posta un commento