Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
M
micropython
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
card10
micropython
Commits
5322ec09
Commit
5322ec09
authored
Mar 9, 2014
by
Damien George
Browse files
Options
Downloads
Patches
Plain Diff
stm: Add DMA support to Audio object.
parent
2da9830b
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
stm/audio.c
+161
-53
161 additions, 53 deletions
stm/audio.c
with
161 additions
and
53 deletions
stm/audio.c
+
161
−
53
View file @
5322ec09
#include
<stdint.h>
#include
<stdint.h>
#include
<string.h>
#include
<string.h>
#include
"stm32f4xx_rcc.h"
#include
"stm32f4xx_gpio.h"
#include
"stm32f4xx_dac.h"
#include
"stm32f4xx_dac.h"
#include
"nlr.h"
#include
"nlr.h"
...
@@ -11,38 +9,34 @@
...
@@ -11,38 +9,34 @@
#include
"qstr.h"
#include
"qstr.h"
#include
"parse.h"
#include
"parse.h"
#include
"obj.h"
#include
"obj.h"
#include
"map.h"
#include
"runtime.h"
#include
"runtime.h"
#include
"audio.h"
#include
"audio.h"
#define SAMPLE_BUF_SIZE (32)
STATIC
void
TIM7_Config
(
uint
freq
)
{
// TIM7 clock enable
RCC_APB1PeriphClockCmd
(
RCC_APB1Periph_TIM7
,
ENABLE
);
// sample_buf_in is always the same or ahead of sample_buf_out
// reset TIM7
// when they are the same, there are no more samples left to process
TIM_DeInit
(
TIM7
);
// in this scheme, there is always 1 unusable byte in the buffer, just before sample_buf_out
int
sample_buf_in
;
int
sample_buf_out
;
byte
sample_buf
[
SAMPLE_BUF_SIZE
];
bool
audio_is_full
(
void
)
{
// Compute the prescaler value so TIM7 triggers at freq-Hz
return
((
sample_buf_in
+
1
)
%
SAMPLE_BUF_SIZE
)
==
sample_buf_out
;
uint16_t
period
=
(
uint16_t
)
((
SystemCoreClock
/
2
)
/
freq
)
-
1
;
}
void
audio_fill
(
byte
sample
)
{
// Time base configuration
sample_buf
[
sample_buf_in
]
=
sample
;
TIM_TimeBaseInitTypeDef
TIM_TimeBaseStructure
;
sample_buf_in
=
(
sample_buf_in
+
1
)
%
SAMPLE_BUF_SIZE
;
TIM_TimeBaseStructure
.
TIM_Period
=
period
;
// timer triggers with this period
// enable interrupt
TIM_TimeBaseStructure
.
TIM_Prescaler
=
0
;
// timer runs at SystemCoreClock / 2
}
TIM_TimeBaseStructure
.
TIM_ClockDivision
=
0
;
// unused for TIM7
TIM_TimeBaseStructure
.
TIM_CounterMode
=
TIM_CounterMode_Up
;
// unused for TIM7
TIM_TimeBaseInit
(
TIM7
,
&
TIM_TimeBaseStructure
);
void
audio_drain
(
void
)
{
// TIM7 TRGO selection
if
(
sample_buf_in
==
sample_buf_out
)
{
TIM_SelectOutputTrigger
(
TIM7
,
TIM_TRGOSource_Update
);
// buffer is empty; disable interrupt
}
else
{
// TIM7 enable counter
// buffer has a sample; output it
TIM_Cmd
(
TIM7
,
ENABLE
);
byte
sample
=
sample_buf
[
sample_buf_out
];
DAC_SetChannel2Data
(
DAC_Align_8b_R
,
sample
);
sample_buf_out
=
(
sample_buf_out
+
1
)
%
SAMPLE_BUF_SIZE
;
}
}
}
/******************************************************************************/
/******************************************************************************/
...
@@ -50,13 +44,67 @@ void audio_drain(void) {
...
@@ -50,13 +44,67 @@ void audio_drain(void) {
typedef
struct
_pyb_audio_t
{
typedef
struct
_pyb_audio_t
{
mp_obj_base_t
base
;
mp_obj_base_t
base
;
int
dac_id
;
// 1 or 2
uint
dac_channel
;
// DAC_Channel_1 or DAC_Channel_2
DMA_Stream_TypeDef
*
dma_stream
;
// DMA1_Stream6 or DMA1_Stream7
}
pyb_audio_t
;
}
pyb_audio_t
;
mp_obj_t
pyb_audio_noise
(
mp_obj_t
self_in
,
mp_obj_t
freq
)
{
pyb_audio_t
*
self
=
self_in
;
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config
(
mp_obj_get_int
(
freq
));
DAC_Cmd
(
self
->
dac_channel
,
DISABLE
);
DAC_InitTypeDef
DAC_InitStructure
;
DAC_InitStructure
.
DAC_Trigger
=
DAC_Trigger_T7_TRGO
;
DAC_InitStructure
.
DAC_WaveGeneration
=
DAC_WaveGeneration_Noise
;
DAC_InitStructure
.
DAC_LFSRUnmask_TriangleAmplitude
=
DAC_LFSRUnmask_Bits10_0
;
DAC_InitStructure
.
DAC_OutputBuffer
=
DAC_OutputBuffer_Enable
;
DAC_Init
(
self
->
dac_channel
,
&
DAC_InitStructure
);
DAC_Cmd
(
self
->
dac_channel
,
ENABLE
);
if
(
self
->
dac_channel
==
DAC_Channel_1
)
{
DAC_SetChannel1Data
(
DAC_Align_12b_L
,
0x7ff0
);
}
else
{
DAC_SetChannel2Data
(
DAC_Align_12b_L
,
0x7ff0
);
}
return
mp_const_none
;
}
mp_obj_t
pyb_audio_triangle
(
mp_obj_t
self_in
,
mp_obj_t
freq
)
{
pyb_audio_t
*
self
=
self_in
;
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config
(
mp_obj_get_int
(
freq
));
DAC_Cmd
(
self
->
dac_channel
,
DISABLE
);
DAC_InitTypeDef
DAC_InitStructure
;
DAC_InitStructure
.
DAC_Trigger
=
DAC_Trigger_T7_TRGO
;
DAC_InitStructure
.
DAC_WaveGeneration
=
DAC_WaveGeneration_Triangle
;
DAC_InitStructure
.
DAC_LFSRUnmask_TriangleAmplitude
=
DAC_TriangleAmplitude_1023
;
DAC_InitStructure
.
DAC_OutputBuffer
=
DAC_OutputBuffer_Enable
;
DAC_Init
(
self
->
dac_channel
,
&
DAC_InitStructure
);
DAC_Cmd
(
self
->
dac_channel
,
ENABLE
);
// set base value of triangle wave
if
(
self
->
dac_channel
==
DAC_Channel_1
)
{
DAC_SetChannel1Data
(
DAC_Align_12b_R
,
0x100
);
}
else
{
DAC_SetChannel2Data
(
DAC_Align_12b_R
,
0x100
);
}
return
mp_const_none
;
}
// direct access to DAC
// direct access to DAC
mp_obj_t
pyb_audio_dac
(
mp_obj_t
self_in
,
mp_obj_t
val
)
{
mp_obj_t
pyb_audio_dac
(
mp_obj_t
self_in
,
mp_obj_t
val
)
{
pyb_audio_t
*
self
=
self_in
;
pyb_audio_t
*
self
=
self_in
;
if
(
self
->
dac_
id
==
1
)
{
if
(
self
->
dac_
channel
==
DAC_Channel_
1
)
{
DAC_SetChannel1Data
(
DAC_Align_8b_R
,
mp_obj_get_int
(
val
));
DAC_SetChannel1Data
(
DAC_Align_8b_R
,
mp_obj_get_int
(
val
));
}
else
{
}
else
{
DAC_SetChannel2Data
(
DAC_Align_8b_R
,
mp_obj_get_int
(
val
));
DAC_SetChannel2Data
(
DAC_Align_8b_R
,
mp_obj_get_int
(
val
));
...
@@ -64,27 +112,92 @@ mp_obj_t pyb_audio_dac(mp_obj_t self_in, mp_obj_t val) {
...
@@ -64,27 +112,92 @@ mp_obj_t pyb_audio_dac(mp_obj_t self_in, mp_obj_t val) {
return
mp_const_none
;
return
mp_const_none
;
}
}
mp_obj_t
pyb_audio_is_full
(
mp_obj_t
self_in
)
{
#define DAC_DHR8R1_ADDRESS (DAC_BASE + 0x10)
if
(
audio_is_full
())
{
#define DAC_DHR8R2_ADDRESS (DAC_BASE + 0x1c)
return
mp_const_true
;
// initiates a burst of RAM->DAC using DMA
// input data is treated as an array of bytes (8 bit data)
// TIM7 is used to set the frequency of the transfer
mp_obj_t
pyb_audio_dma
(
uint
n_args
,
const
mp_obj_t
*
args
,
mp_map_t
*
kw_args
)
{
pyb_audio_t
*
self
=
args
[
0
];
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config
(
mp_obj_get_int
(
args
[
2
]));
mp_obj_type_t
*
type
=
mp_obj_get_type
(
args
[
1
]);
if
(
type
->
buffer_p
.
get_buffer
==
NULL
)
{
nlr_jump
(
mp_obj_new_exception_msg
(
&
mp_type_TypeError
,
"buffer argument must support buffer protocol"
));
}
buffer_info_t
bufinfo
;
type
->
buffer_p
.
get_buffer
(
args
[
1
],
&
bufinfo
,
BUFFER_READ
);
RCC_AHB1PeriphClockCmd
(
RCC_AHB1Periph_DMA1
,
ENABLE
);
DMA_Cmd
(
self
->
dma_stream
,
DISABLE
);
while
(
DMA_GetCmdStatus
(
self
->
dma_stream
)
!=
DISABLE
)
{
}
DAC_Cmd
(
self
->
dac_channel
,
DISABLE
);
// DAC channel configuration
DAC_InitTypeDef
DAC_InitStructure
;
DAC_InitStructure
.
DAC_Trigger
=
DAC_Trigger_T7_TRGO
;
DAC_InitStructure
.
DAC_WaveGeneration
=
DAC_WaveGeneration_None
;
DAC_InitStructure
.
DAC_LFSRUnmask_TriangleAmplitude
=
DAC_TriangleAmplitude_1
;
// unused, but need to set it to a valid value
DAC_InitStructure
.
DAC_OutputBuffer
=
DAC_OutputBuffer_Enable
;
DAC_Init
(
self
->
dac_channel
,
&
DAC_InitStructure
);
// DMA1_Stream[67] channel7 configuration
DMA_DeInit
(
self
->
dma_stream
);
DMA_InitTypeDef
DMA_InitStructure
;
DMA_InitStructure
.
DMA_Channel
=
DMA_Channel_7
;
if
(
self
->
dac_channel
==
DAC_Channel_1
)
{
DMA_InitStructure
.
DMA_PeripheralBaseAddr
=
DAC_DHR8R1_ADDRESS
;
}
else
{
}
else
{
return
mp_const_false
;
DMA_InitStructure
.
DMA_PeripheralBaseAddr
=
DAC_DHR8R2_ADDRESS
;
}
}
DMA_InitStructure
.
DMA_Memory0BaseAddr
=
(
uint32_t
)
bufinfo
.
buf
;
DMA_InitStructure
.
DMA_DIR
=
DMA_DIR_MemoryToPeripheral
;
DMA_InitStructure
.
DMA_BufferSize
=
bufinfo
.
len
;
DMA_InitStructure
.
DMA_PeripheralInc
=
DMA_PeripheralInc_Disable
;
DMA_InitStructure
.
DMA_MemoryInc
=
DMA_MemoryInc_Enable
;
DMA_InitStructure
.
DMA_PeripheralDataSize
=
DMA_PeripheralDataSize_Byte
;
DMA_InitStructure
.
DMA_MemoryDataSize
=
DMA_MemoryDataSize_Byte
;
mp_map_elem_t
*
kw_mode
=
mp_map_lookup
(
kw_args
,
MP_OBJ_NEW_QSTR
(
qstr_from_str
(
"mode"
)),
MP_MAP_LOOKUP
);
DMA_InitStructure
.
DMA_Mode
=
kw_mode
==
NULL
?
DMA_Mode_Normal
:
mp_obj_get_int
(
kw_mode
->
value
);
// normal = 0, circular = 0x100
DMA_InitStructure
.
DMA_Priority
=
DMA_Priority_High
;
DMA_InitStructure
.
DMA_FIFOMode
=
DMA_FIFOMode_Disable
;
DMA_InitStructure
.
DMA_FIFOThreshold
=
DMA_FIFOThreshold_HalfFull
;
DMA_InitStructure
.
DMA_MemoryBurst
=
DMA_MemoryBurst_Single
;
DMA_InitStructure
.
DMA_PeripheralBurst
=
DMA_PeripheralBurst_Single
;
DMA_Init
(
self
->
dma_stream
,
&
DMA_InitStructure
);
// enable DMA stream
DMA_Cmd
(
self
->
dma_stream
,
ENABLE
);
while
(
DMA_GetCmdStatus
(
self
->
dma_stream
)
==
DISABLE
)
{
}
}
mp_obj_t
pyb_audio_fill
(
mp_obj_t
self_in
,
mp_obj_t
val
)
{
// enable DAC channel
audio_fill
(
mp_obj_get_int
(
val
));
DAC_Cmd
(
self
->
dac_channel
,
ENABLE
);
// enable DMA for DAC channel
DAC_DMACmd
(
self
->
dac_channel
,
ENABLE
);
//printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
return
mp_const_none
;
return
mp_const_none
;
}
}
STATIC
MP_DEFINE_CONST_FUN_OBJ_2
(
pyb_audio_noise_obj
,
pyb_audio_noise
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_2
(
pyb_audio_triangle_obj
,
pyb_audio_triangle
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_2
(
pyb_audio_dac_obj
,
pyb_audio_dac
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_2
(
pyb_audio_dac_obj
,
pyb_audio_dac
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_1
(
pyb_audio_is_full_obj
,
pyb_audio_is_full
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_KW
(
pyb_audio_dma_obj
,
3
,
pyb_audio_dma
);
STATIC
MP_DEFINE_CONST_FUN_OBJ_2
(
pyb_audio_fill_obj
,
pyb_audio_fill
);
STATIC
const
mp_method_t
pyb_audio_methods
[]
=
{
STATIC
const
mp_method_t
pyb_audio_methods
[]
=
{
{
"noise"
,
&
pyb_audio_noise_obj
},
{
"triangle"
,
&
pyb_audio_triangle_obj
},
{
"dac"
,
&
pyb_audio_dac_obj
},
{
"dac"
,
&
pyb_audio_dac_obj
},
{
"is_full"
,
&
pyb_audio_is_full_obj
},
{
"dma"
,
&
pyb_audio_dma_obj
},
{
"fill"
,
&
pyb_audio_fill_obj
},
{
NULL
,
NULL
},
{
NULL
,
NULL
},
};
};
...
@@ -94,8 +207,8 @@ STATIC const mp_obj_type_t pyb_audio_type = {
...
@@ -94,8 +207,8 @@ STATIC const mp_obj_type_t pyb_audio_type = {
.
methods
=
pyb_audio_methods
,
.
methods
=
pyb_audio_methods
,
};
};
STATIC
const
pyb_audio_t
pyb_audio_channel_1
=
{{
&
pyb_audio_type
},
1
};
STATIC
const
pyb_audio_t
pyb_audio_channel_1
=
{{
&
pyb_audio_type
},
DAC_Channel_1
,
DMA1_Stream5
};
STATIC
const
pyb_audio_t
pyb_audio_channel_2
=
{{
&
pyb_audio_type
},
2
};
STATIC
const
pyb_audio_t
pyb_audio_channel_2
=
{{
&
pyb_audio_type
},
DAC_Channel_2
,
DMA1_Stream6
};
// create the audio object
// create the audio object
// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
// 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) {
...
@@ -106,17 +219,14 @@ STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
int
dac_id
=
mp_obj_get_int
(
id
);
int
dac_id
=
mp_obj_get_int
(
id
);
uint
pin
;
uint
pin
;
uint
channel
;
const
pyb_audio_t
*
dac_obj
;
mp_obj_t
dac_obj
;
if
(
dac_id
==
1
)
{
if
(
dac_id
==
1
)
{
pin
=
GPIO_Pin_4
;
pin
=
GPIO_Pin_4
;
channel
=
DAC_Channel_1
;
dac_obj
=
&
pyb_audio_channel_1
;
dac_obj
=
(
mp_obj_t
)
&
pyb_audio_channel_1
;
}
else
{
}
else
{
pin
=
GPIO_Pin_5
;
pin
=
GPIO_Pin_5
;
channel
=
DAC_Channel_2
;
dac_obj
=
&
pyb_audio_channel_2
;
dac_obj
=
(
mp_obj_t
)
&
pyb_audio_channel_2
;
}
}
// DAC channel configuration
// DAC channel configuration
...
@@ -130,19 +240,17 @@ STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
...
@@ -130,19 +240,17 @@ STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
DAC_InitTypeDef
DAC_InitStructure
;
DAC_InitTypeDef
DAC_InitStructure
;
DAC_InitStructure
.
DAC_Trigger
=
DAC_Trigger_None
;
DAC_InitStructure
.
DAC_Trigger
=
DAC_Trigger_None
;
DAC_InitStructure
.
DAC_WaveGeneration
=
DAC_WaveGeneration_None
;
DAC_InitStructure
.
DAC_WaveGeneration
=
DAC_WaveGeneration_None
;
DAC_InitStructure
.
DAC_LFSRUnmask_TriangleAmplitude
=
DAC_TriangleAmplitude_1023
;
DAC_InitStructure
.
DAC_OutputBuffer
=
DAC_OutputBuffer_Enable
;
DAC_InitStructure
.
DAC_OutputBuffer
=
DAC_OutputBuffer_Enable
;
DAC_Init
(
channel
,
&
DAC_InitStructure
);
DAC_Init
(
dac_obj
->
dac_
channel
,
&
DAC_InitStructure
);
// Enable DAC Channel
// Enable DAC Channel
DAC_Cmd
(
channel
,
ENABLE
);
DAC_Cmd
(
dac_obj
->
dac_
channel
,
ENABLE
);
// from now on use DAC_SetChannel[12]Data to trigger a conversion
// from now on use DAC_SetChannel[12]Data to trigger a conversion
sample_buf_in
=
0
;
sample_buf_out
=
0
;
// return static object
// return static object
return
dac_obj
;
return
(
mp_obj_t
)
dac_obj
;
}
}
MP_DEFINE_CONST_FUN_OBJ_1
(
pyb_Audio_obj
,
pyb_Audio
);
MP_DEFINE_CONST_FUN_OBJ_1
(
pyb_Audio_obj
,
pyb_Audio
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment