PICOのPIOを使った指定周期DMAによるシリアラル信号出力プログラムについて
PICOのPIOを使ったPWM信号出力をDMAで動作させる方法について備忘録
注:PIOを使ったPICOのPWM機能をDMAで動作させる方法はいまいちわからなかった。(というか、PIOのTX FIFOにデータを送った場合、PIOはGPIOピンに0/1信号しか出せず、PWMレジスターに値を書き込めない。そもそもDMAには自己完結型のDREQインターバル設定ができるので、DMAでPWMレジスターに値を書き込むだけなら、PIOは特に必要ないかも。。。)
ここではPIOに32ビットデータを1ビットずつ設定した周期でGPIO出力させることでPWM信号を作る方法について備忘録する。
- DMAはDREQによってDMA転送を1データ単位(32ビット)ごとに実行する。
- DMAは自らのDMAインターバルによってDREQを自動発生することもできる。
- channel_config_set_dreq(&pwm_dma_chan_config, DREQ_PWM_WRAP0 + led_pwm_slice_num)
- DMA ch構成では、転送ソースアドレス、転送ターゲットアドレス、転送カウントを設定する。
- dma_channel_configure(
dma_chan, // DMAチャネル
&dma_chan_config, // DMAチャネル構成情報
&pio0_hw->txf[state_machine_id], // PIOのTX FIFO
// &pwm_hw->slice[led_pwm_slice_num].cc, // PWMレジスタの場合
data_table, // データ元
256, // 転送カウント
false // スタートタイミング(即時スタートの場合はtrue)
);
- dma_channel_configure(
- DMAは設定した転送カウント分の転送が完了するとIRQを発生する。
- このIRQを使って次回DMA転送するデータを設定する。
- PIOはTX FIFOの1データ単位(32ビット)を取り出す。
- 32ビットを1ビット取り出すにはshiftを使う
- channel_config_set_transfer_data_size(&dma_chan_config, DMA_SIZE_32);
新しくTX FIFOからデータを取り出すまで1ビットずつシフトし1ビットずつとりだす動作を32ビット行う
- channel_config_set_transfer_data_size(&dma_chan_config, DMA_SIZE_32);
- PIOのTX FIFOが空になるとDREQを発生させる。
- channel_config_set_dreq(&pwm_dma_chan_config, DREQ_PIO0_TX0);
- 上記と以下は等価
channel_config_set_dreq(&pwm_dma_chan_config, pio_get_dreq(pio, state_machine_id, true));
- 対象とするDMA chにこのDREQを紐付けることでTX FIFOが空になるごとにDMAを行うようにする
======= Program 1 DMAだけ、IRQなし =======
Main C Program
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#include <hello.pio.h>
int main()
{
PIO pio = pio0;
uint state_machine_id = 0;
uint offset = pio_add_program(pio, &pio_dac_program);
pio_dac_program_init(pio, state_machine_id, offset, PICO_DEFAULT_LED_PIN, 2000.f);
int pwm_dma_chan = dma_claim_unused_channel(true);
dma_channel_config dma_chan_config = dma_channel_get_default_config(pwm_dma_chan);
channel_config_set_transfer_data_size(&dma_chan_config, DMA_SIZE_32);
channel_config_set_read_increment(&dma_chan_config, true);
channel_config_set_write_increment(&dma_chan_config, false);
channel_config_set_dreq(&dma_chan_config, pio_get_dreq(pio, state_machine_id, true)); // pio sm, TX
dma_channel_configure(
dma_chan,
&dma_chan_config,
&pio0_hw->txf[state_machine_id],
data_table,
256,
false
);
dma_channel_set_read_addr(dma_chan, mark_tab, true); // DMAをスタートする
while(true) {
tight_loop_contents();
}
}
PIO Program
.program pio_dac
.wrap_target
out pins, 1
.wrap
% c-sdk {
static inline void pio_dac_program_init(PIO pio, uint sm, uint offset, uint pin, float fs) {
pio_sm_config c = pio_dac_program_get_default_config(offset);
sm_config_set_out_shift(&c, true, true, 32);
sm_config_set_out_pins(&c, pin, 1);
// sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); これはなくても動作は同じ
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / fs);
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}
======= Program 2 DMAとIRQの両方 =======
Main C Program
// そのおかげでメインプログラムはデータ転送を気にすることなく他のタスクが実行可能となる
◆ dma_channel_set_read_addr()
|
inlinestatic |
Set the DMA initial read address.
- Parameters
-
channel DMA channel read_addr Initial read address of transfer. trigger True to start the transfer immediately
cmake_minimum_required(VERSION 3.16) //使っている環境が3.16だからとりあえず3.16に設定
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(led_fade C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_subdirectory(led_fade)
add_executable(led_fade
led_fade.c
)
pico_generate_pio_header(led_fade ${CMAKE_CURRENT_LIST_DIR}/hello.pio)
target_link_libraries(led_fade
pico_stdlib
hardware_pio
hardware_dma
)
pico_add_extra_outputs(led_fade)
======= Program 3 文字列を波形出力する =======
« PICOのPWMをDMAで動作させる方法 | トップページ | pico_tnc 2200Hz(Space)でPhaseをずらす件の備忘録 »
「ラズパイ日記」カテゴリの記事
- NEO-7M GPSモジュールが中国から届いた(2023.01.15)
- TNCアプリにおけるDemoduatorの動作確認(2023.01.09)
- AFSKでの復調について(2023.01.04)
- APRSでのNRZIについて備忘録(2023.01.02)
- pico_tnc 2200Hz(Space)でPhaseをずらす件の備忘録(2022.12.31)
« PICOのPWMをDMAで動作させる方法 | トップページ | pico_tnc 2200Hz(Space)でPhaseをずらす件の備忘録 »
コメント