2014-03-18 10:29 PM
2014-03-19 05:08 AM
A bunch of issues in there,
To generate a 20 KHz signal with 10 samples, you need to output the samples at 200 KHz. The TIM prescaler should be the smaller factor of prescaler and period, ideally if within 16-bit range the prescaler should be zero (DIV1). Period = (SystemCoreClock / 200000) - 1; for 200 KHz where TIMCLK = CPUCLK You need to set the Update as the Trigger source. You need to enable the GPIOA clock prior to configuration, AN mode is sufficient. The DMA needs to point at an address, *wavetable is the content, you want (uint32_t)wavetable or (uint32_t)&wavetable[0], I'd use the form (uint32_t)&DAC->DR for the peripheral. No need to use interrupts unless you plan to do something with them, ie change table I'd tinker, but the supplied code isn't sufficiently complete.2014-03-19 11:13 AM
2014-03-19 12:23 PM
So 240 -1, the Prescaler and Period expect N-1 values
The DAC drives the DMA through the external trigger, in this case one from the timer with a connectivity defined at each end of the connection. If you set the DAC to trigger on TIMx_TRGO then you need to configure the timer end of that contract. You could alternatively use TIMx_CCx, or use a DMA channel driven by a timer directly. There are a myriad of options here to permit multiple devices to be synchronized, ie ADC, DAC, and multiple channels thereof. The DMA expects addresses, use the ampersand (&) to do this in C ie not (uint32_t) DAC->DHR8R1; but (uint32_t)&DAC->DHR8R1; Completeness, observe the examples I have posted, they are stand-alone, and compile. They are placed in the body of the message using the ''Format Code Block'' tool.2014-03-19 01:16 PM
// STM32F0-Discovery Single DAC 6.25 KHz Sine - sourcer32@gmail.com
#include ''stm32f0_discovery.h''
//**************************************************************************************
const uint16_t Sine12bit[32] = {
2047, 2447, 2831, 3185,
3498, 3750, 3939, 4056,
4095, 4056, 3939, 3750,
3495, 3185, 2831, 2447,
2047, 1647, 1263, 909,
599, 344, 155, 38,
0, 38, 155, 344,
599, 909, 1263, 1647};
//**************************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure PA4 in analogue (output) mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /* overkill? */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//**************************************************************************************
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
int Period;
/* TIM2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
Period = (SystemCoreClock / 200000); // 200 KHz timebase, 6.25 KHz Sine
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // not relevant here
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 TRGO selection: update event is selected as trigger for DAC */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
//**************************************************************************************
void DAC_Configuration(void)
{
DAC_InitTypeDef DAC_InitStructure;
/* DAC Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/* Fill DAC InitStructure */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; /* Select the receiving end */
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
/* DAC channel1 Configuration */
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/* Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is
automatically connected to the DAC converter. */
DAC_Cmd(DAC_Channel_1, ENABLE);
/* Enable DMA for DAC Channel2 */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
//**************************************************************************************
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 32;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/* Enable DMA1 Channel3 */
DMA_Cmd(DMA1_Channel3, ENABLE);
}
//**************************************************************************************
int main(void)
{
GPIO_Configuration();
DMA_Configuration();
DAC_Configuration();
TIM_Configuration();
/* Infinite loop */
while(1);
}
//**************************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
2014-03-19 01:19 PM
// STM32F0-Discovery Single DAC 20 KHz Sine - sourcer32@gmail.com
#include ''stm32f0_discovery.h''
//**************************************************************************************
const uint16_t Sine12bit[32] = {
2047, 2447, 2831, 3185,
3498, 3750, 3939, 4056,
4095, 4056, 3939, 3750,
3495, 3185, 2831, 2447,
2047, 1647, 1263, 909,
599, 344, 155, 38,
0, 38, 155, 344,
599, 909, 1263, 1647};
//**************************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure PA4 in analogue (output) mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /* overkill? */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//**************************************************************************************
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
int Period;
/* TIM2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
Period = (SystemCoreClock / (20000 * 32)); // 20 KHz Sine, 32 sample wave table
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // not relevant here
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 TRGO selection: update event is selected as trigger for DAC */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
//**************************************************************************************
void DAC_Configuration(void)
{
DAC_InitTypeDef DAC_InitStructure;
/* DAC Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/* Fill DAC InitStructure */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; /* Select the receiving end */
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
/* DAC channel1 Configuration */
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/* Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is
automatically connected to the DAC converter. */
DAC_Cmd(DAC_Channel_1, ENABLE);
/* Enable DMA for DAC Channel2 */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
//**************************************************************************************
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 32;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/* Enable DMA1 Channel3 */
DMA_Cmd(DMA1_Channel3, ENABLE);
}
//**************************************************************************************
int main(void)
{
GPIO_Configuration();
DMA_Configuration();
DAC_Configuration();
TIM_Configuration();
/* Infinite loop */
while(1);
}
//**************************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
2014-03-20 02:03 PM
Thank you Clive1. Very helpful.
2014-03-21 10:32 AM
2014-03-21 10:54 AM
#1 - That's going to be hard, as they don't route. This is why I'd use TIM2, 3 or 15 if I wanted to tie the ADC and DAC together
#2 - There are limited resources and connectivity, part of the task is to manage them, and fit the solution. #3 - I'm not a big fan of the double buffer scheme, it's designed to allow for a scatter-gather or DMA chaining, where you have a longer list of buffers to manage. I prefer to double the buffer size and use it in a Ping-Pong fashion, with the HT (Half Transfer), TC (Transfer Compete), but this depends on the in-flow and out-flow rates expected. I've posted other STM32 ADC examples that illustrate some of these concepts.
2014-03-21 01:33 PM
Clive,
Yes, the longer buffer seems like a better idea. BTW, what is the deal with you? You have over 8,000 post. Do you work for ST? Thanks a million! -Mike