1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

STM32F4のTIMでPWMを出してDACっぽく使うサンプル

Posted at

使用リソース

  • PB6
  • TIM3(Basic)
  • TIM4(PWM)
  • DMA1 ch5

TIM4 ch1をPB6に接続してPWMを出力し、外部のLPFで平滑します。また、TIM3でタイミングを作ってDMAをトリガすることで、周期的にPWMのパルス幅を変更します。

ソースコード

constexpr uint16_t period = 42;

constexpr uint16_t buff_len = 25;
static uint16_t buff[buff_len] = {};

for (uint32_t i = 0; i < buff_len; i++)
{
    buff[i] = static_cast<uint16_t>(
        period * 0.5f +
        period * 0.5f * 0.8f * sinf(static_cast<float>(i) / buff_len * 3.141592f * 2.f) +
        0.5f);
}

__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();

GPIO_InitTypeDef gpio = {
    .Pin = GPIO_PIN_6,
    .Mode = GPIO_MODE_AF_PP,
    .Pull = GPIO_NOPULL,
    .Speed = GPIO_SPEED_HIGH,
    .Alternate = GPIO_AF2_TIM4};
HAL_GPIO_Init(GPIOB, &gpio);

TIM_HandleTypeDef htim1 = {
    .Instance = TIM4,
    .Init = TIM_Base_InitTypeDef{
        .Prescaler = 0,
        .CounterMode = TIM_COUNTERMODE_UP,
        .Period = period - 1}};
HAL_TIM_PWM_Init(&htim1);

TIM_OC_InitTypeDef oc = {
    .OCMode = TIM_OCMODE_PWM1,
    .Pulse = period / 2 - 1};
HAL_TIM_PWM_ConfigChannel(&htim1, &oc, TIM_CHANNEL_1);

TIM_HandleTypeDef htim2 = {
    .Instance = TIM3,
    .Init = TIM_Base_InitTypeDef{
        .Prescaler = 0,
        .CounterMode = TIM_COUNTERMODE_UP,
        .Period = 84 - 1}};
HAL_TIM_Base_Init(&htim2);

__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_UPDATE);

DMA_HandleTypeDef hdma = {
    .Instance = DMA1_Stream2,
    .Init = DMA_InitTypeDef{
        .Channel = DMA_CHANNEL_5,
        .Direction = DMA_MEMORY_TO_PERIPH,
        .PeriphInc = DMA_PINC_DISABLE,
        .MemInc = DMA_MINC_ENABLE,
        .PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD,
        .MemDataAlignment = DMA_MDATAALIGN_HALFWORD,
        .Mode = DMA_CIRCULAR,
        .Priority = DMA_PRIORITY_MEDIUM,
        .FIFOMode = DMA_FIFOMODE_DISABLE}};
HAL_DMA_Init(&hdma);

HAL_DMA_Start(&hdma,
                reinterpret_cast<uint32_t>(buff),
                reinterpret_cast<uint32_t>(&htim1.Instance->CCR1),
                buff_len);

HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_Base_Start(&htim2);

結果

SDS00012.png

黄色がPWM出力、紫色がCR LPFの後ろです(以下同様)。

168MHzのコアで、2分周がTIMに入り、42分周しているので、2MHzのPWMが出力されています。デューティー比50%付近では三角波状になっていますね。


SDS00013.png

2MHzなので1周期500ナノ秒、50%で250ナノ秒、のパルスでトリガしています。

PWMに対して通常のエッジトリガを使うと、アナログ波形の位相がロックされず、見づらくなってしまうので、パルス幅でトリができるオシロがあると便利です。アナログ波形のエッジでトリガした場合はPWMの位相がロックされなくなってしまうので、パルス幅でトリガしたほうが見やすいです。


SDS00011.png

波形転送は1MHzで行い、25ポイントで1周期なので、40kHzのピークが出ています。高調波も出ていますが-40dB程度であまり問題はないと思います。


SDS00010.png

PWMが2MHzなので、その付近にもピークが出ています。40kHzの第2高調波よりも高く出ています。


今回は2MHzから40kHzを出しているので、50倍程度の差となり、1段のCR LPFでは高周波成分を除去しきれていません。PWM周波数を上げれば多少は改善しますが、今度はデューティー分解能が低下してしまいます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?