目標
STM32F4のDACから2chの正弦波をTIMのタイミングで出す。
CubeMXの設定
Pinoutタブ
DACからOUT1 ConfigurationとOUT2 Configurationのチェックを入れる。
TIM4のInternal Clockにチェックを入れる。
Configurationタブ
AnalogのDACボタンをクリック、DAC Configurationウインドウを開く。
Parameter SettingsタブでDAC Out1 SettingsとDAC Out2 SettingsのTriggerをTimer 4 Trigger Out eventにする。
DMA SettingsタブでAddをクリックしDMA RequestをDAC1にする。同じ手順でDAC2のDMAも作る。
OkでDAC Configurationウインドウを閉じる。
ControlのTIM4ボタンをクリック、TIM4 Configurationウインドウを開く。
Prescalerに84-1
、Counter Periodに1000-1
にする。
Trigger Event SelectionでUpdate Eventを選択する。
OkでTIM4 Configurationウインドウを閉じる。
コードを書き出す。
ソースコード
constexpr size_t len(1000);
static int16_t DAC1_buff[len];
static int16_t DAC2_buff[len];
for (size_t i(0); i < len; ++i)
{
const float s(sinf((float)i / len * pi * 2));
DAC1_buff[i] = (int16_t)(+s * 1800 + 2048);
DAC2_buff[i] = (int16_t)(-s * 1800 + 2048);
}
HAL_TIM_GenerateEvent(&htim4, TIM_EVENTSOURCE_UPDATE);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC1_buff, len, DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)DAC2_buff, len, DAC_ALIGN_12B_R);
HAL_TIM_Base_Start(&htim4);
while (__HAL_DMA_GET_COUNTER(hdac.DMA_Handle1) > 0 &&
__HAL_DMA_GET_COUNTER(hdac.DMA_Handle2) > 0)
{
osDelay(1);
}
HAL_TIM_Base_Stop(&htim4);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_2);
結果
DAC1とDAC2をオシロで見てみた。
1000ポイントで正弦波1周期を1kSPSで出力しているので、1secで1周期の正弦波となるが、正しくそのように出力されている。
その他
今回はNormalモードだが、CircularにすればDACバッファを延々と送信し続けることができる。今回の例をCircularにすると1Hzの正弦波が延々と送信されることになる。
また、今回は12bitモードだが、8bitモードにすることもできる。その場合、使用するメモリが半分で済むので、電圧分解能がそれほど高くなくていいなら8bitモードは良い選択肢になる。また、バス使用率が半分になるのも利点。