CubeMXでDACとTIM7を有効化する。
DACの初期化
DACはOUT1を有効化し、TriggerにTimer 7 Trigger Out eventを指定する。DMA SettingsでDAC1のDMAを追加し、Circularモードに設定する。
TIM7の初期化
TIM7はTrigger Event SelectionをUpdate Eventに設定。
クロック
Clock ConfigでHCLKを168MHzになるように設定。
適当なタイミングで以下のコードを実行する。
const double timer_clock = 84e6;
const uint16_t timer_PSC = 0;
const uint16_t timer_ARR = 84 - 1;
const double sin_frequency_Hz = 2000;
const double sin_offset = 2048;
const double sin_mag = 1800;
const double pi = 3.1415926535897932384626433832795;
htim7.Instance->PSC = timer_PSC;
htim7.Instance->ARR = timer_ARR;
HAL_TIM_GenerateEvent(&htim7, TIM_EVENTSOURCE_UPDATE);
double sampling_rate = timer_clock / (htim7.Instance->ARR + 1) / (htim7.Instance->PSC + 1);
int32_t length = (int32_t)round(sampling_rate / sin_frequency_Hz);
int16_t *DAC_buff = malloc(sizeof(int16_t) * length);
for (int16_t i = 0; i < length; i++)
{
double a = sin(i / (double)length * pi * 2) * sin_mag + sin_offset;
if (a < 0)
{
a = 0;
}
if (a > 4095)
{
a = 4095;
}
DAC_buff[i] = (int16_t)a;
}
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC_buff, length, DAC_ALIGN_12B_R);
HAL_TIM_Base_Start(&htim7);
このコードだと2kHzの正弦波が出力される。
sin_frequency_Hzを変更すればある程度の範囲で設定できる。
あまりに遅いと大量のメモリが必要になるので、その場合はtimer_PSCとtimer_ARRで設定する。
timer_clockが84MHzでPSC=0, ARR=84-1の場合、サンプリングレートは1Mspsになる。2kHzの正弦波を出す場合は500ポイントのデータが生成される。int16_tなので、1KiBのメモリが必要になる。
100Hzの正弦波の場合は10kPoint、20KiBのメモリが必要になる。その場合はtimer_PSC=10-1にすれば、1kPoint、2KiBで済む。
C言語なのでmallocで確保しているが、C++ならconstexprでコンパイル時に計算できるので、固定長配列として確保でき、メモリを使用すぎるとコンパイラエラーにできる。