STM32f030k wave player - Page 1
Forum section: electronics / general

author: alizare368
author_rank: Regular Contributor
timestamp: December 11, 2019, 04:10:59 pm
content: Hi everybodyI want to make a wave player with stm32f030k ,I read the data correctly fro SD .and I put the data in the buffers,and send to PWM.I read and send ping pong data.the Timer 14 adjusted to interrupt white frequency =44100 proportional to sample rate. F=48mhz/44100=1088The prescaler register is 1088 for generate interrupt.the timer 3 adjusted for PWM generate in channel 1 and 2, the prescaler register is 255.I want to launch as a single channel.the MCU clock is 48MHZ .the main code is in the section below.Code:#include "main.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include "stdio.h"#include "low_level.h"#include "ff.h"#include "diskio.h"FATFS fs;FIL myfile;/* USER CODE END Includes *//* Private variables ---------------------------------------------------------*/SPI_HandleTypeDef hspi1;TIM_HandleTypeDef htim3;TIM_HandleTypeDef htim14;/* USER CODE BEGIN PV *//* USER CODE BEGIN 0 */#define sample_no 256uint8_t sai_buf;uint8_t index_buf=0;uint8_t refill=0;uint32_t bt;/* USER CODE END 0 */int main(void){/* USER CODE BEGIN 1 */static FRESULT myfres=1;/* USER CODE END 1 *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_TIM3_Init();MX_TIM14_Init();/* USER CODE BEGIN 2 *//* USER CODE BEGIN 2 */HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,0);myfres=disk_initialize(0);myfres=f_mount(0, &fs);myfres=f_open(&myfile,"1.wav",FA_READ);myfres=f_read(&myfile,&sai_buf,sample_no,&bt);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);HAL_TIM_Base_Start_IT(&htim14);/* USER CODE END 2 */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if(refill){index_buf++;myfres=f_read(&myfile,&sai_buf[index_buf%2],sample_no,&bt);refill=0;}}/* USER CODE END 3 */}This function handles TIM14 global interrupt.proportional whit f=44100 sample rate.Code:void TIM14_IRQHandler(void){/* USER CODE BEGIN TIM14_IRQn 0 *//* USER CODE END TIM14_IRQn 0 */HAL_TIM_IRQHandler(&htim14);/* USER CODE BEGIN TIM14_IRQn 1 */TIM3->CCR1=sai_buf[index_buf%2];TIM3->CCR2=sai_buf[index_buf%2][i+1];i+=4;if(i>=(sample_no-1)){i=0;refill = 1;}/* USER CODE END TIM14_IRQn 1 */}In this project, the PWM Combination circuit is composed of two resitors: 1M and 3.9K. And the summing ratio is about 8:1. The larger resistor is connected to LSB PWM output channel while the smaller resistor is connected to MSB PWM channel.the output resistor combination and sound is attached in the following file.What idea do you have for solving this problem??

author: jhpadjustable
author_rank: Frequent Contributor
timestamp: December 11, 2019, 06:06:03 pm
content: Have you tried larger buffers? Have you experimented with a larger chip? Have you timed any of the major processes in this design with a timer, particularly, the interrupt itself and the f_read call? (The systick timer is excellent for this, even if you leave the interrupt disabled.) What experimentation or troubleshooting have you done? In particular, what have you done to prove the core aspects of your design and to test their logical pieces independently? Do you know whether the MSB alone works? Can you play back a clean sine output stored in ROM at 8 bits? 16 bits?Finally, have you priced out 16-bit audio DACs? (They're like 15 cents.)

author: Yansi
author_rank: Super Contributor
timestamp: December 11, 2019, 06:19:52 pm
content: Why that? There are tons of commercially available modules to do just this, with same poor performance will likely get out of this.If this is worth doing, then why don't do it properly?Get yourself an I2S equipped microcontroller and use any of the cheap I2S DACs, such as CS4334.There are heaps of even small STM32 Cortex M0 MCUs with I2S peripheral.(And with STM32, beware of the retarded integrated MCLK generator peripheral - can't be used for shit - workaround for it is to use the system clock as an audio rate multiple, such as 12.288MHz HSE, instead of 12MHz. Or to use a DAC such that can generate LRCK, BCK and MCLK itself, with the I2S peripheral in slave mode. Otherwise you will end up with very imprecise sample rate).

author: jhpadjustable
author_rank: Frequent Contributor
timestamp: December 11, 2019, 07:41:38 pm
content: Quote from: Yansi on December 11, 2019, 06:19:52 pmIn this case I'd use a cheap, plain R/2R serial DAC that doesn't need MCLK, like the TM8211/PT8211 or equivalent, which could be driven with the unadorned SPI port and a bit-banged LRCK.

author: Yansi
author_rank: Super Contributor
timestamp: December 11, 2019, 07:55:32 pm
content: The distortion of these R2R is quite poor. Yes, better than the original OPs idea, but still miserable. Not sure what the OP wants this for, but I would not go for worse than CS4334 as a "audio wav player" is concerned.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 11, 2019, 08:06:40 pm
content: From what I remember, the OP has already tried using a true DAC in the past and was already having some trouble (eg.:https://www.eevblog.com/forum/microcontrollers/help-to-resolve-24-bit-192-khz-stereo-da-converter/)

author: Yansi
author_rank: Super Contributor
timestamp: December 12, 2019, 12:17:11 am
content: Thank you for pointing that out, I might write up some suggestions for him. Working out a simple I2S DAC shall indeed be simple, using STM32 with HW I2S peripheral and with DMA.I might even try, I have a bunch of CS4334 in my stash. Just need to solder a simple adapter for it. If the OP wants to help with that? Please let me know.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 12, 2019, 12:42:13 am
content: Yes, using an I2S DAC like this would be way better in terms of sound quality and still pretty straightforward to use. IMO in both cases, the OP seems to have some troubles with properly sequencing reading from the SD card, and sending buffers to the DAC (or using PWM) without getting audible gaps. There are a few things to get right, including a double buffering scheme.

author: Yansi
author_rank: Super Contributor
timestamp: December 12, 2019, 08:49:36 pm
content: Unfortunately, now before Xmas I have not much free time, so probably I could make the practical tests with CS4334 only later, not now. (I do not have any PCB with the CS4334 on it, I would have to make something - too lazy and too little time for that - OP would have to wait for any specific source code examples)Using an I2S DAC with a DMA futter shall be pretty straightforward. So what I suggest to the OP to do:Switch from STM32F030 to say F042. F030 does not have I2S interface, F042 does. Unfortunately, neither of those has SDIO peripheral to interface an SD card, SPI solution shall be okay for this case, but not necessarily always, especially with an awfully slow file system stack, such as the popular fatfs from ElmChan.Use an audio rate multiple frequency of the HSE crystal. Say you will stick with the industry standard multiple of 8kHz of sample rate: I suggest 48 kHz for simplicity. "44k1 CD quality" shit shall never be used as a system base rate, it is a non standard and no longer used in audio equipment. Avoid at all cost. (Either way, even computers from back when with AC97 sound codecs used 48kHz. CD was input in analog form from the CD-ROM tray directly, or resampled in digital domain to the system rate of 48kHz).For 48kHz audio, the most standard way is to use a 256fs, meaning a MCLK frequency of 256*48000 = 12 288 000 Hz. Such crystals are widely available. Use one for the HSE oscillator. As the F042 is simple little MCU, it has only a single oscillator and single PLL, there are two options: Clock the CPU either from HSI at 48MHz (imprecise frequency derived from an internal RC oscillator - HSI) or clock the cpu from the HSE (12.288MHz) at about 48MHz. (you can either get 49.152MHz with multiplying by four with the PLL which might work no problems for a diy project, but for a commercial product, stay below the maximum of 48MHz!)Use the MCO (PA8) output of the stm32 to output the HSE frequency (12.288MHz) directly (do not use the PLL divided back!) and stick this output to the MCLK input of the DAC (presumably a CS4334 or similar).Configure the I2S interface GPIO pins, configure the I2S peripheral in master transmit mode (only the SD (PA7), CK (PA5) and WS (PA4) pins), with the bit clock generator set for correct speed. Refer to the reference manual:QuoteWhen I2SxCLK (same as HCLK) is 49.152MHz: to obtain 48kHz, you need to in total divide by: 49 152 000 / 48 000 = 1024.To obtain 48kHz with 16bit data: Frame length is 32, so I2SDIV = 1024/32/2 = 16, ODD=0To obtain 48kHz with 24bit data: Frame length is 64, so I2SDIV = 1024/64/2 = 8, ODD=0.Configure the rest of I2S accordingly.For a continuous data stream to the I2S peripheral, you need a DMA. Configure the DMA1 Channel 3 to serve the SPI1_TX request. Use a circular buffer mode, enable interrupts both for Halftransfer- and Transfer complete interrupts.Both of these interrupts are served be the same interrupt vector (function). Should work like this: You fill one half of the circular buffer, while the other half is being transmitted out! On the entry to the interrupt service routine, you check, which of the halves shall be filled (detect either HTIF or TCIF flag set and do not forget to clear it via the DMA_IFCR register).Within the interrupt routine, you are supposed to fill just one half of the buffer. If you are using the fatfs library, be aware that fatfs is not thread safe (as far as I can tell), so it is not possible to use its functions both from interrupt or from main.Using the file read functions within the interrupt is a bad idea any way, as the access times for data are non deterministic and data shall be pre-buffered in a separate and large enough data buffer to accomodate access time variation. Also, using an interrupt to waste time waiting for a lazy file system stack and the card to spit data, is bad programming practice. Do not waste time within interrupts.The audio DMA buffer size shall be picked such, that your interrupt rate is acceptable one, for your application. For example, if the sample rate is 48kHz and the whole buffer is of size 256 samples (1024Byte for 16bit data or 2048B for 24b (32b respectively) data), the interrupt will fire every 256/2 = 128 samples, ie every 48000 / 128 = 375 times per second.That is completely acceptable, and the throughput data delay will be 128/48000 = 2.67 ms. In this case, the delay does not matter, but if you would also be processing data from an ADC input, then the processing delay might be critical for intended operation of the device. (it would not be acceptable to make a digital guitar effect with a processing delay of say 100ms - you could not just play with it).//EDIT: Important note! MCLK input of the DAC, shall be synchronous to the I2S interface bit clock. It does not have to be phase aligned in any way, but needs to be synchronous. That means, the I2S_CLKmustbe run off of a PLL, that has the audio frequency crystal as its source. Otherwise it won't be synchronous and will cause trouble. I forgot this is a single PLL simple microcontroller, I am not used to working with audio on these funny small ones. Sorry for the misconception in the above writing, HSI must not be used as the PLL source. Otherwise, you won't get correct sample rate anyway, the MCU is the I2S master, dictating the sample rate.

author: alizare368
author_rank: Regular Contributor
timestamp: December 14, 2019, 01:07:45 pm
content: HiI want to design with PWM ,not I2S. because it should be low cost.I have already used I2S and I got the answer.

author: OwO
author_rank: Super Contributor
timestamp: December 14, 2019, 04:46:03 pm
content: I would try delta sigma modulation. Can be done on stm32f0 by using DMA GPIO. I think something like a 2-bit resistor DAC (for 4 levels) should make the noise not audible and not cause a lot of distortion.

author: alizare368
author_rank: Regular Contributor
timestamp: December 16, 2019, 06:11:53 pm
content: HiHow can I do this with DMA GPIO??

author: Yansi
author_rank: Super Contributor
timestamp: December 16, 2019, 06:18:17 pm
content: Why all this? You are not gonna get cheaper then dedicated single chip solutions from far east.And how about the integrated 12b DAC?

author: alizare368
author_rank: Regular Contributor
timestamp: December 16, 2019, 06:49:10 pm
content: I have to use DAC again. :-

author: Yansi
author_rank: Super Contributor
timestamp: December 16, 2019, 07:45:59 pm
content: So what? DAC comes free in many of your STM32 micros.Hard to suggest you anything, if you are being cryptic about your goals.

author: jhpadjustable
author_rank: Frequent Contributor
timestamp: December 16, 2019, 08:16:32 pm
content: Quote from: Yansi on December 16, 2019, 07:45:59 pmIn the F0x1 series, at least, 36-pin and smaller packages have only one DAC output. Two DAC outputs are available in 48-pin and larger packages. The F030 has no DACs.I agree this project seems to lack a goal. If OP is unwilling to measure or observe anything that is going on under the hood, instead just throwing their idea at the chip and complaining vaguely that it doesn't work, what help is there to give?

author: alizare368
author_rank: Regular Contributor
timestamp: December 17, 2019, 05:34:26 pm
content: Hi guysI think the problem is in reading the SD CARD, SPI speed is low.I want to set up spi with register, for more speed.but when I write the code in the registry ,I can't read the data from SD CARD.when I write the code like this,It's work fine , I read the data from SD CARD.this function in low_level.c.Code:uint8_t SPI_1(uint8_t data){uint8_t rxd,txd;txd= data;HAL_SPI_TransmitReceive(&hspi1,txd,rxd,1,100);return rxd;}But When I write like this, I can't read the data from SD CARD.Code:uint8_t SPI_1(uint8_t data){uint8_t rxd,txd;txd= data;SPI1->DR =txd;while((SPI1->SR & 0x83)!=0x03);//waite for end of the Transrxd=SPI1->DR;return rxd;}when myfres=f_open(&myfile,"6.wav",FA_READ); is called. myfres=FR_INVALID_OBJECTWhat do you think is the problem???