11#include <stdint.h>
22#include <string.h>
33
4- #include "stm32f4xx_rcc.h"
5- #include "stm32f4xx_gpio.h"
64#include "stm32f4xx_dac.h"
75
86#include "nlr.h"
119#include "qstr.h"
1210#include "parse.h"
1311#include "obj.h"
12+ #include "map.h"
1413#include "runtime.h"
1514
1615#include "audio.h"
1716
18- #define SAMPLE_BUF_SIZE (32)
17+ STATIC void TIM7_Config (uint freq ) {
18+ // TIM7 clock enable
19+ RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM7 , ENABLE );
1920
20- // sample_buf_in is always the same or ahead of sample_buf_out
21- // when they are the same, there are no more samples left to process
22- // in this scheme, there is always 1 unusable byte in the buffer, just before sample_buf_out
23- int sample_buf_in ;
24- int sample_buf_out ;
25- byte sample_buf [SAMPLE_BUF_SIZE ];
21+ // reset TIM7
22+ TIM_DeInit (TIM7 );
2623
27- bool audio_is_full (void ) {
28- return ((sample_buf_in + 1 ) % SAMPLE_BUF_SIZE ) == sample_buf_out ;
29- }
24+ // Compute the prescaler value so TIM7 triggers at freq-Hz
25+ uint16_t period = (uint16_t ) ((SystemCoreClock / 2 ) / freq ) - 1 ;
3026
31- void audio_fill (byte sample ) {
32- sample_buf [sample_buf_in ] = sample ;
33- sample_buf_in = (sample_buf_in + 1 ) % SAMPLE_BUF_SIZE ;
34- // enable interrupt
35- }
27+ // Time base configuration
28+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure ;
29+ TIM_TimeBaseStructure .TIM_Period = period ; // timer triggers with this period
30+ TIM_TimeBaseStructure .TIM_Prescaler = 0 ; // timer runs at SystemCoreClock / 2
31+ TIM_TimeBaseStructure .TIM_ClockDivision = 0 ; // unused for TIM7
32+ TIM_TimeBaseStructure .TIM_CounterMode = TIM_CounterMode_Up ; // unused for TIM7
33+ TIM_TimeBaseInit (TIM7 , & TIM_TimeBaseStructure );
3634
37- void audio_drain (void ) {
38- if (sample_buf_in == sample_buf_out ) {
39- // buffer is empty; disable interrupt
40- } else {
41- // buffer has a sample; output it
42- byte sample = sample_buf [sample_buf_out ];
43- DAC_SetChannel2Data (DAC_Align_8b_R , sample );
44- sample_buf_out = (sample_buf_out + 1 ) % SAMPLE_BUF_SIZE ;
45- }
35+ // TIM7 TRGO selection
36+ TIM_SelectOutputTrigger (TIM7 , TIM_TRGOSource_Update );
37+
38+ // TIM7 enable counter
39+ TIM_Cmd (TIM7 , ENABLE );
4640}
4741
4842/******************************************************************************/
4943// Micro Python bindings
5044
5145typedef struct _pyb_audio_t {
5246 mp_obj_base_t base ;
53- int dac_id ; // 1 or 2
47+ uint dac_channel ; // DAC_Channel_1 or DAC_Channel_2
48+ DMA_Stream_TypeDef * dma_stream ; // DMA1_Stream6 or DMA1_Stream7
5449} pyb_audio_t ;
5550
51+ mp_obj_t pyb_audio_noise (mp_obj_t self_in , mp_obj_t freq ) {
52+ pyb_audio_t * self = self_in ;
53+
54+ // set TIM7 to trigger the DAC at the given frequency
55+ TIM7_Config (mp_obj_get_int (freq ));
56+
57+ DAC_Cmd (self -> dac_channel , DISABLE );
58+
59+ DAC_InitTypeDef DAC_InitStructure ;
60+ DAC_InitStructure .DAC_Trigger = DAC_Trigger_T7_TRGO ;
61+ DAC_InitStructure .DAC_WaveGeneration = DAC_WaveGeneration_Noise ;
62+ DAC_InitStructure .DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits10_0 ;
63+ DAC_InitStructure .DAC_OutputBuffer = DAC_OutputBuffer_Enable ;
64+ DAC_Init (self -> dac_channel , & DAC_InitStructure );
65+
66+ DAC_Cmd (self -> dac_channel , ENABLE );
67+
68+ if (self -> dac_channel == DAC_Channel_1 ) {
69+ DAC_SetChannel1Data (DAC_Align_12b_L , 0x7ff0 );
70+ } else {
71+ DAC_SetChannel2Data (DAC_Align_12b_L , 0x7ff0 );
72+ }
73+
74+ return mp_const_none ;
75+ }
76+
77+ mp_obj_t pyb_audio_triangle (mp_obj_t self_in , mp_obj_t freq ) {
78+ pyb_audio_t * self = self_in ;
79+
80+ // set TIM7 to trigger the DAC at the given frequency
81+ TIM7_Config (mp_obj_get_int (freq ));
82+
83+ DAC_Cmd (self -> dac_channel , DISABLE );
84+
85+ DAC_InitTypeDef DAC_InitStructure ;
86+ DAC_InitStructure .DAC_Trigger = DAC_Trigger_T7_TRGO ;
87+ DAC_InitStructure .DAC_WaveGeneration = DAC_WaveGeneration_Triangle ;
88+ DAC_InitStructure .DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023 ;
89+ DAC_InitStructure .DAC_OutputBuffer = DAC_OutputBuffer_Enable ;
90+ DAC_Init (self -> dac_channel , & DAC_InitStructure );
91+
92+ DAC_Cmd (self -> dac_channel , ENABLE );
93+
94+ // set base value of triangle wave
95+ if (self -> dac_channel == DAC_Channel_1 ) {
96+ DAC_SetChannel1Data (DAC_Align_12b_R , 0x100 );
97+ } else {
98+ DAC_SetChannel2Data (DAC_Align_12b_R , 0x100 );
99+ }
100+
101+ return mp_const_none ;
102+ }
103+
56104// direct access to DAC
57105mp_obj_t pyb_audio_dac (mp_obj_t self_in , mp_obj_t val ) {
58106 pyb_audio_t * self = self_in ;
59- if (self -> dac_id == 1 ) {
107+ if (self -> dac_channel == DAC_Channel_1 ) {
60108 DAC_SetChannel1Data (DAC_Align_8b_R , mp_obj_get_int (val ));
61109 } else {
62110 DAC_SetChannel2Data (DAC_Align_8b_R , mp_obj_get_int (val ));
63111 }
64112 return mp_const_none ;
65113}
66114
67- mp_obj_t pyb_audio_is_full (mp_obj_t self_in ) {
68- if (audio_is_full ()) {
69- return mp_const_true ;
115+ #define DAC_DHR8R1_ADDRESS (DAC_BASE + 0x10)
116+ #define DAC_DHR8R2_ADDRESS (DAC_BASE + 0x1c)
117+
118+ // initiates a burst of RAM->DAC using DMA
119+ // input data is treated as an array of bytes (8 bit data)
120+ // TIM7 is used to set the frequency of the transfer
121+ mp_obj_t pyb_audio_dma (uint n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
122+ pyb_audio_t * self = args [0 ];
123+
124+ // set TIM7 to trigger the DAC at the given frequency
125+ TIM7_Config (mp_obj_get_int (args [2 ]));
126+
127+ mp_obj_type_t * type = mp_obj_get_type (args [1 ]);
128+ if (type -> buffer_p .get_buffer == NULL ) {
129+ nlr_jump (mp_obj_new_exception_msg (& mp_type_TypeError , "buffer argument must support buffer protocol" ));
130+ }
131+ buffer_info_t bufinfo ;
132+ type -> buffer_p .get_buffer (args [1 ], & bufinfo , BUFFER_READ );
133+
134+ RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_DMA1 , ENABLE );
135+
136+ DMA_Cmd (self -> dma_stream , DISABLE );
137+ while (DMA_GetCmdStatus (self -> dma_stream ) != DISABLE ) {
138+ }
139+
140+ DAC_Cmd (self -> dac_channel , DISABLE );
141+
142+ // DAC channel configuration
143+ DAC_InitTypeDef DAC_InitStructure ;
144+ DAC_InitStructure .DAC_Trigger = DAC_Trigger_T7_TRGO ;
145+ DAC_InitStructure .DAC_WaveGeneration = DAC_WaveGeneration_None ;
146+ DAC_InitStructure .DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1 ; // unused, but need to set it to a valid value
147+ DAC_InitStructure .DAC_OutputBuffer = DAC_OutputBuffer_Enable ;
148+ DAC_Init (self -> dac_channel , & DAC_InitStructure );
149+
150+ // DMA1_Stream[67] channel7 configuration
151+ DMA_DeInit (self -> dma_stream );
152+ DMA_InitTypeDef DMA_InitStructure ;
153+ DMA_InitStructure .DMA_Channel = DMA_Channel_7 ;
154+ if (self -> dac_channel == DAC_Channel_1 ) {
155+ DMA_InitStructure .DMA_PeripheralBaseAddr = DAC_DHR8R1_ADDRESS ;
70156 } else {
71- return mp_const_false ;
157+ DMA_InitStructure . DMA_PeripheralBaseAddr = DAC_DHR8R2_ADDRESS ;
72158 }
73- }
159+ DMA_InitStructure .DMA_Memory0BaseAddr = (uint32_t )bufinfo .buf ;
160+ DMA_InitStructure .DMA_DIR = DMA_DIR_MemoryToPeripheral ;
161+ DMA_InitStructure .DMA_BufferSize = bufinfo .len ;
162+ DMA_InitStructure .DMA_PeripheralInc = DMA_PeripheralInc_Disable ;
163+ DMA_InitStructure .DMA_MemoryInc = DMA_MemoryInc_Enable ;
164+ DMA_InitStructure .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte ;
165+ DMA_InitStructure .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ;
166+ mp_map_elem_t * kw_mode = mp_map_lookup (kw_args , MP_OBJ_NEW_QSTR (qstr_from_str ("mode" )), MP_MAP_LOOKUP );
167+ DMA_InitStructure .DMA_Mode = kw_mode == NULL ? DMA_Mode_Normal : mp_obj_get_int (kw_mode -> value ); // normal = 0, circular = 0x100
168+ DMA_InitStructure .DMA_Priority = DMA_Priority_High ;
169+ DMA_InitStructure .DMA_FIFOMode = DMA_FIFOMode_Disable ;
170+ DMA_InitStructure .DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull ;
171+ DMA_InitStructure .DMA_MemoryBurst = DMA_MemoryBurst_Single ;
172+ DMA_InitStructure .DMA_PeripheralBurst = DMA_PeripheralBurst_Single ;
173+ DMA_Init (self -> dma_stream , & DMA_InitStructure );
174+
175+ // enable DMA stream
176+ DMA_Cmd (self -> dma_stream , ENABLE );
177+ while (DMA_GetCmdStatus (self -> dma_stream ) == DISABLE ) {
178+ }
179+
180+ // enable DAC channel
181+ DAC_Cmd (self -> dac_channel , ENABLE );
182+
183+ // enable DMA for DAC channel
184+ DAC_DMACmd (self -> dac_channel , ENABLE );
185+
186+ //printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
74187
75- mp_obj_t pyb_audio_fill (mp_obj_t self_in , mp_obj_t val ) {
76- audio_fill (mp_obj_get_int (val ));
77188 return mp_const_none ;
78189}
79190
191+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (pyb_audio_noise_obj , pyb_audio_noise );
192+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (pyb_audio_triangle_obj , pyb_audio_triangle );
80193STATIC MP_DEFINE_CONST_FUN_OBJ_2 (pyb_audio_dac_obj , pyb_audio_dac );
81- STATIC MP_DEFINE_CONST_FUN_OBJ_1 (pyb_audio_is_full_obj , pyb_audio_is_full );
82- STATIC MP_DEFINE_CONST_FUN_OBJ_2 (pyb_audio_fill_obj , pyb_audio_fill );
194+ STATIC MP_DEFINE_CONST_FUN_OBJ_KW (pyb_audio_dma_obj , 3 , pyb_audio_dma );
83195
84196STATIC const mp_method_t pyb_audio_methods [] = {
197+ { "noise" , & pyb_audio_noise_obj },
198+ { "triangle" , & pyb_audio_triangle_obj },
85199 { "dac" , & pyb_audio_dac_obj },
86- { "is_full" , & pyb_audio_is_full_obj },
87- { "fill" , & pyb_audio_fill_obj },
200+ { "dma" , & pyb_audio_dma_obj },
88201 { NULL , NULL },
89202};
90203
@@ -94,8 +207,8 @@ STATIC const mp_obj_type_t pyb_audio_type = {
94207 .methods = pyb_audio_methods ,
95208};
96209
97- STATIC const pyb_audio_t pyb_audio_channel_1 = {{& pyb_audio_type }, 1 };
98- STATIC const pyb_audio_t pyb_audio_channel_2 = {{& pyb_audio_type }, 2 };
210+ STATIC const pyb_audio_t pyb_audio_channel_1 = {{& pyb_audio_type }, DAC_Channel_1 , DMA1_Stream5 };
211+ STATIC const pyb_audio_t pyb_audio_channel_2 = {{& pyb_audio_type }, DAC_Channel_2 , DMA1_Stream6 };
99212
100213// create the audio object
101214// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
@@ -106,17 +219,14 @@ STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
106219
107220 int dac_id = mp_obj_get_int (id );
108221 uint pin ;
109- uint channel ;
110- mp_obj_t dac_obj ;
222+ const pyb_audio_t * dac_obj ;
111223
112224 if (dac_id == 1 ) {
113225 pin = GPIO_Pin_4 ;
114- channel = DAC_Channel_1 ;
115- dac_obj = (mp_obj_t )& pyb_audio_channel_1 ;
226+ dac_obj = & pyb_audio_channel_1 ;
116227 } else {
117228 pin = GPIO_Pin_5 ;
118- channel = DAC_Channel_2 ;
119- dac_obj = (mp_obj_t )& pyb_audio_channel_2 ;
229+ dac_obj = & pyb_audio_channel_2 ;
120230 }
121231
122232 // DAC channel configuration
@@ -130,19 +240,17 @@ STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
130240 DAC_InitTypeDef DAC_InitStructure ;
131241 DAC_InitStructure .DAC_Trigger = DAC_Trigger_None ;
132242 DAC_InitStructure .DAC_WaveGeneration = DAC_WaveGeneration_None ;
243+ DAC_InitStructure .DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023 ;
133244 DAC_InitStructure .DAC_OutputBuffer = DAC_OutputBuffer_Enable ;
134- DAC_Init (channel , & DAC_InitStructure );
245+ DAC_Init (dac_obj -> dac_channel , & DAC_InitStructure );
135246
136247 // Enable DAC Channel
137- DAC_Cmd (channel , ENABLE );
248+ DAC_Cmd (dac_obj -> dac_channel , ENABLE );
138249
139250 // from now on use DAC_SetChannel[12]Data to trigger a conversion
140251
141- sample_buf_in = 0 ;
142- sample_buf_out = 0 ;
143-
144252 // return static object
145- return dac_obj ;
253+ return ( mp_obj_t ) dac_obj ;
146254}
147255
148256MP_DEFINE_CONST_FUN_OBJ_1 (pyb_Audio_obj , pyb_Audio );
0 commit comments