2016-06-27 10:01 AM
Hi.
I am trying to output a sine using the DAC of my STM32 F334R8. I spent days trying to do so with the example in the SPL. This example uses a button (which is not present on my board) to switch between, in one hand, a sine and an escalator waveform (using respectively channel 1 and 2), and in other hand noise and triangle waveform (using both channels too). I thought it would be ok if I just isolated the waveform I wanted, but it turned out it was not. What I did just now is to use a code kindly provided on [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/sawtooth&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=97]an older thread by clive1 to generate a sinewave using both channels. It was not the same device, so I adjusted it the best I could, and it almost works, I think. The problem is, my amplitude is ridiculously low: circa 3 mV. When I do the proper adjustments on the oscilloscope, it almost looks like a very ugly sine, but I think this is mainly noise. Honestly I don't know what I could do. My goal is to have a sine with an amplitude of 3.3 V, and a frequency of, let's say 1 or 10 kHz. I have tried many things, many codes, tried to get familiar with the device by using some easier examples, but eventually I'm always stuck there. Here is the code I came up with, if you see some huge mistake or anything please point them out:
#include ''main.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};
uint16_t SineTable[64];
/**************************************************************************/
void
RCC_Config(
void
)
{
/* DMA1 clock and GPIOA clock enable (to be used with DAC) */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* DAC and TIM6 Peripheral clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);
}
/**************************************************************************/
void
GPIO_Config(
void
)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************/
void
TIM6_Config(
void
)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
int
Period;
Period = ((SystemCoreClock / 2) / 200000);
// 200 KHz timebase, 6.25 KHz Sine
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
/* TIM6 TRGO selection */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
/* TIM6 enable counter */
TIM_Cmd(TIM6, ENABLE);
}
/**************************************************************************/
#define DAC_DHR12RD_ADDRESS 0x40007428 // Right Align 12-bit Dual
void
DAC_Config(
void
)
{
DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* DAC channel 1 and 2 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
// DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //doesn't exist with standard libraries
DAC_InitStructure.DAC_Buffer_Switch = DAC_BufferSwitch_Enable;
DAC_Init(DAC1, DAC_Channel_1, &DAC_InitStructure);
DAC_Init(DAC1, DAC_Channel_2, &DAC_InitStructure);
/* DMA1_channel3 configuration **************************************/
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SineTable;
DMA_InitStructure.DMA_BufferSize = 32;
// 16-bit x 64 / 2
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
// 32-bit 16x2
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/* Enable DMA1_Channel3 */
DMA_Cmd(DMA1_Channel3, ENABLE);
/* Enable DAC Channel 1 and 2 */
DAC_Cmd(DAC1, DAC_Channel_1, ENABLE);
DAC_Cmd(DAC1, DAC_Channel_2, ENABLE);
/*If I comment the two lines above, almost nothing change in the signal I see. I take it as an evidence this code doesn't work at all */
/* Enable DMA for DAC Channel1 */
DAC_DMACmd(DAC1, DAC_Channel_1, ENABLE);
}
/**************************************************************************/
int
main(
void
)
{
int
i, j;
j = 0;
for
(i=0; i<32; i++)
{
SineTable[j++] = Sine12bit[i];
SineTable[j++] = Sine12bit[(i + 8) % 32];
// 90 degree phase shift on Channel 2
}
RCC_Config();
GPIO_Config();
TIM6_Config();
DAC_Config();
while
(1);
// Do not exit
}
- i don't understand how the dual mode works: how does the DAC know it is supposed to outputs each case of the table alternatively in each channel?
- What is the point of doing that, rather than using just one channel?
- My stm32f30x_tim.h specifically says that the basic TIM_TimeBaseInitTypeDef; is ''
used with all TIMx except for TIM6 and TIM7.'' So i changed it for TIM2, which doesn't work either.
Besides, how am I supposed to use the Timer 6 and 7? How do they work? I only know they are basic timers dedicated to DAC, but nothing about how to use it, how to implement it.
- If i have in fact the value 4095 in the table, I suppose I should see a max of 3.3 V. Why is it not the case?
- How do i know if the table is even read? I'm not sure I know how to interprete correctly the debug mode.
I have more or less the same result when I use the code from the example.
I wonder if something could be wrong in the startup file or something like that.
Thank you.
2016-06-28 08:22 AM
Single Up example at 6 KHz
// STM32F3-Discovery Single DAC 6 KHz Sine - sourcer32@gmail.com
//****************************************************************************
#include ''stm32f3_discovery.h''
uint16_t Sine12bit[32] = { // Table must be in RAM for F3 DMA
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 RCC_Config(void)
{
/* DMA1 clock and GPIOA clock enable (to be used with DAC) */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* DAC and TIM6 Peripheral clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);
}
//****************************************************************************
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* DAC channel 1 (DAC_OUT1 = PA.4) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//****************************************************************************
void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
int Period;
Period = (SystemCoreClock / 192000); // 192 KHz timebase, 6 KHz Sine
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
/* TIM6 TRGO selection */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
/* TIM6 enable counter */
TIM_Cmd(TIM6, ENABLE);
}
//****************************************************************************
void DAC_Config(void)
{
DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* DAC channel 1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits11_0;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/* DMA1_channel3 configuration **************************************/
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1; //DAC channel1 12-bit right-aligned
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit[0];
DMA_InitStructure.DMA_BufferSize = 32; // 16-bit x 32
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
/*Remap TIM6/DAC1 DMA requests from DMA2 channel 3 to DMA1 channel 3 */
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM6DAC1, ENABLE);
/* Enable DMA1_Channel3 */
DMA_Cmd(DMA1_Channel3, ENABLE);
/* Enable DAC Channel 1 */
DAC_Cmd(DAC_Channel_1, ENABLE);
/* Enable DMA for DAC Channel1 */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
//****************************************************************************
int main(void)
{
RCC_Config();
GPIO_Config();
TIM6_Config();
DAC_Config();
while(1); // Do not exit
}
//****************************************************************************
#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
//****************************************************************************
2016-06-29 06:10 AM
Thanks, Clive, I think I get it now :)
I also managed to use the user button as an external interrupt in order to change the frequency of the signal at each push. :)