前回はDACの開始と同時にADCも開始する方法を紹介しました。この方法は気軽な半面、ADCを遅れて開始させることができません。
電線に通す電気信号のような、非常に高速に伝搬する信号であれば問題ありませんが、例えば超音波距離計のような、伝搬速度がある程度遅い経路を通す場合等、ADCを遅れて動作させたほうが良い時があります。
ということで、今回はDACから遅れてADCを動作させます。
CubeMXの設定
DAC(マスタ)はTIM4で駆動し、ADC(スレーブ)はTIM3で動作させています。つまり、TIM4をマスタにしつつ、TIM3をスレーブにできるTIMxを間に挟むことにより、任意時間のディレイを実現できます。
この条件に一致するTIMはTIM2とTIM5のどちらかです。幸運なことにTIM2/TIM5はどちらも32bitカウンタを持っているので、柔軟な運用ができます。どちらもTIM3/TIM4と連番なのでどちらを使ってもあまり違和感はありませんが、とりあえず今回はTIM5を使用することにします。
Pinoutタブ
TIM5のSlave ModeをTrigger Modeに、Trigger SourceをITR2に、そしてInternal ClockとOne Pulse Modeにチェックを入れます。
TIM3のTrigger SourceをITR2にします。
Configurationタブ
TIM5をクリックし、TIM5 Configurationウインドウを開きます。
Trigger Event SelectionをUpdate Eventにします。
これでCubeMXの設定は終了です。コードを書き出してソフトウェアの変更に移ります。
ソースコード
constexpr size_t DAC_len(1000);
constexpr size_t ADC_len(1000);
static uint8_t DAC1_buff[DAC_len];
static uint8_t DAC2_buff[DAC_len];
static uint16_t ADC_buff[ADC_len];
for (size_t i(0); i < DAC_len; ++i)
{
const float s(sinf((float)i / DAC_len * pi * 2));
DAC1_buff[i] = (uint8_t)(+s * 110 + 128);
DAC2_buff[i] = (uint8_t)(-s * 110 + 128);
}
memset(ADC_buff, 0, sizeof(ADC_buff));
htim5.Instance->ARR = 84 * 1000 * 250 - 1;
HAL_TIM_GenerateEvent(&htim4, TIM_EVENTSOURCE_UPDATE);
HAL_TIM_Base_Stop(&htim5);
HAL_TIM_GenerateEvent(&htim5, TIM_EVENTSOURCE_UPDATE);
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_GenerateEvent(&htim3, TIM_EVENTSOURCE_UPDATE);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC1_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)DAC2_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_buff, ADC_len);
HAL_TIM_Base_Start(&htim4);
while (__HAL_DMA_GET_COUNTER(hdac.DMA_Handle1) > 0 ||
__HAL_DMA_GET_COUNTER(hdac.DMA_Handle2) > 0 ||
__HAL_DMA_GET_COUNTER(hadc1.DMA_Handle) > 0)
{
osDelay(1);
}
HAL_TIM_Base_Stop(&htim4);
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_Base_Stop(&htim5);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_2);
HAL_ADC_Stop_DMA(&hadc1);
for (size_t i(0); i < ADC_len; ++i)
{
printf("%u %hu\n", i, ADC_buff[i]);
}
ソースコードは前回のものとほぼ同様です。
TIM5のARR設定/クリア/Start/Stopが増えたのが違いです。
この設定によりDACから250msec遅れてADCが開始されます。
今回は250msecですが、コアクロック168MHzの場合、プリスケーラ無しで最大50秒程度、プリスケーラも併用する場合は最大約6千年分のディレイができます。
例えばプリスケーラを84-1
に設定した場合、1マイクロ秒の分解能で1時間程度までディレイできるので、大抵の場合はこの設定で問題ないはずです。
深宇宙の探査機と通信したい、みたいな場合はもうちょっとディレイ時間が長いほうが嬉しいかもしれないですね。そのような場合は各自調整してください。
結果
前回のグラフと比べて、ADCが250msec遅れて(波形が250msec進んで)計測されていることがわかります。
履歴
2018-06-19
- 転送終了待ちwhileの条件を修正