Rapsberry Piの記録領域はハードウェアの性質上、基本的にはSDカードをまるまるひとつ使用します。運用中なのであれば、マルチメディアファイルなど、システムとは関係のないファイルもまとめてSDカードに保存してもよいのですが、しばしばシステムの入れ替えが必要となる開発環境では、入れ替えのたびに、ファイルを保存し直さないといけません。そこでパーティションツールを使ってSDカードに作業領域を確保する方法のひとつを紹介します。

まずは、OSイメージを書き込んだSDカードを用意します。ここで特別な設定は不要です。
Rapberry Piで起動し、初期設定を終えたら、以下のコマンドでコンフィグツールを起動します。
sudo raspi-config
メニューから「7 Advanced options/A1 Expand Filesystem Ensures that all of the SD card storage is available」を選択すると、SDカードの空き領域がすべてシステムに割り当てられます。
このカードから作業領域を確保してみます。このままだとロックがかかっているので、電源を切ったらSDカードを抜いて、USBカードリーダーなどの外部リーダーへつなぎ直します。WindowsではLinuxのディスクフォーマットであるext4に柔軟に対応できるツールがないので、Linuxからパーティションツールを動かすことになります。

Raspberry Pi単体であればもうひとつOSを入れたメモリーカードが必要となりますが、パソコンを使えばUSBメモリーからライブブートしたUbuntuや仮想マシン上のRaspbian Desktopなどが使えます。

パーティションの変更手順を誤ってしまうとブート自体ができなくなってしまうので、パーティションのバックアップをとっておきます。今回はMiniTool社のご厚意で「MiniTool Partition Wizard」を使うことができたので、こちらでササッとパーティションを丸ごとコピーすることで対応したいと思います。

メインウィンドウのメニューより「ウィザード/パーティションのコピー」を選択し、ウィザード画面でSDカードのext4領域を指定。
コピー先ディスクの空き領域を指定。
大容量ハードディスクであれば、環境や履歴ごとのバックアップもできます。
また、ディスクコピー機能を使えば、同容量かそれ以上のメモリーカードへシステムを丸ごと複写することができるので、取っかえ引っかえでシステムを運用することもできるでしょう。

ここからのスクリーンショットはVirtualBoxでRapbian Desktopを動かしたものです。Linux用GUIパーティションツール「GParted」をインストールしたら、アプリを起動します。
sudo apt install gparted
sudo gparted
パソコンにつないだSDカードのディスクを指定し、ext4パーティションに対して「リサイズ/移動」を選びます。
「前方の空き領域」は維持したまま、「新しいサイズ」の値を変更し、「後方の空き容量」を確保したいサイズにまで増やします。
ついでに確保した後方領域をFAT32でフォーマットしてみました。
すべての操作を適用」でタスクを実行しないと反映されないので注意しましょう。

これでシステムトラブルなどでシステムを入れ直す必要が出てきても、バックアップしたパーティションだけを移し直せば、作業領域のファイルは保持されたままになります。
 | 2019年9月20日

IntelやAMDを問わず、上位モデルのマザーボードには光デジタルオーディオ出力端子が備わっています。一方で廉価モデルにはアナログ入出力端子しかないように思えますが、おおかたのマザーボードではRealtekのオーディオチップが搭載されており、そのチップの性能に差はありません。そのため、エントリーモデルのマザーボードにも光オーディオ出力端子がピンとして備わっているのがあり、そこから電気信号を取り出すことで光オーディオ端子を増設することができます。

Amazonでは「S/PDIF ブラケット」という名称で増設ポートが売られていますが、この端子は自作できます。

自作に必要なパーツは以下の通り。
共立電子では基板付きのキットが400円程度で販売されているので、こちらを使えば手っ取り早く制作できます。
データシートに従い、VCCとGND端子をコンデンサーでつなぎ、適度な長さに切ったケーブルを送信モジュールの端子に半田付けします。
これをマザーボードのマニュアルに従って「5V」と「VCC」、「SPDIFOUT」と「IN」、「GND」同士をつなぎます(写真はASUS PRIME B450)。
これだけで増設は完了です。接続に問題がなければ、マザーボードの電源を入れると、このモジュールから赤い光が出てくるので、市販の光オーディオケーブルを接続してください。

ちなみにRealtekのドライバーだと、Windows 10でDolby DIgitalやdtsといったマルチチャンネルオーディオが有効になりませんが、これはソフトウェアレベルで対処することができます。

エンコーダーアプリを使用する:オープンソースプロジェクトの「AC3Filter」を使えばエンコードしたデータを光オーディオ端子に直接出力できるようになります。

ドライバーにパッチを当てる:Realtekの公式ドライバーに有志が作ったパッチを当てて、エンコード出力をWindows 10でも使えるようにします。ただし、この方法ではセキュリティー上の懸念が生じるため、このブログではパッチへのリンク紹介は控えます。興味のある方は「Pihto」をキーワードに、自己責任にて探してみてください。

入手したパッチソフトを適用するには、公式ドライバーを展開した先のフォルダーにコピーしてから実行(Windows 10サンドボックス、もしくは仮想マシンでの実行を推奨)し、パッチ適用後に通常のインストーラーを起動させます。
パッチが正しく適用されていれば、デジタルオーディオ出力プロパティ画面にステレオ以外の候補が表示されます。
 | 2019年9月17日

WSLことWindows Subsystem for LinuxではWindows 10でLinuxバイナリを実行させることができます。GUIをリモート描画するX Serverを利用すれば、Linux GUIベースのQtアプリもWindowsマシンで開発・デバッグすることができるようになります。ただし、WSL1では、ハードウェアを制御するようなプログラムの開発はできません。

まずはコントロールパネルの「プログラムと機能」の「Windows機能の有効化」より「Windows Subsystem for Linux」をインストールし、マイクロソフトストアよりLinuxディストリビューションをインストールします。今回の解説ではDebianを導入しています。これ以外のディストリビューションではインストールする必要のあるパッケージが異なる可能性があります。
Debianを起動したら、まずはパッケージをダウンロードするために必要なネットワークアプリを導入します。
sudo apt update sudo apt install wget
GUIおよび開発ツール、デバッガーをインストールします。
sudo apt install dbus sudo apt install x11-apps sudo apt install libxkbcommon-x11-0 sudo apt install libx11-xcb-dev sudo apt install libglu1-mesa-dev -y sudo apt install libglib2.0-0 sudo apt install libfontconfig1 sudo apt install build-essential sudo apt install clang sudo apt install gdb
GUIをリモート表示するためのX Server(VcXsrv)をWindows側にインストールします。

XLaunch.exeを起動すると設定画面が表示されます。基本的に初期設定のままでかまいませんが、nVidia(GeForce)のグラフィックカードを利用している場合、OpenGL関連のエラーが発生することがあるので、そのような場合は「Native opengl」のチェックを外しましょう。
Debianの「~/.bashrc」をテキストエディタなどで開き、最後の行に「export DISPLAY=:0.0」の一文を追加することで、X Serverの接続先を定義します。上書き保存したら、Debianを再起動させましょう。
Qtのパッケージをダウンロードし、実行権限を与えてアプリを実行させます。ここではLTSの5.12.4を指定していますが、必要に応じてこのバージョン数値は変更してください。
wget http://download.qt.io/official_releases/qt/5.12/5.12.4/qt-opensource-linux-x64-5.12.4.run chmod +x qt-opensource-linux-x64-5.12.4.run ./qt-opensource-linux-x64-5.12.4.run
関連ライブラリーが正しく導入されていれば、インストーラーが起動するので、あとはLinux上と同じように手続きを踏んでいきます。

QtCreatorを起動するにはコンソールで「~/(Qtのインストール先)/Tools/QtCreator/bin/qtcreator」と入力します。
ちなみにWindowsにあるファイルをWSLで使用するには、cpコマンドでファイルを移動させておく必要があります。
cp -r /mnt/c/src/ /home/dst/
逆にWSLからWindowsへファイルを移動させたい場合はDebianで以下のコマンドを実行してエクスプローラーにマウントさせます(Windows 10 May 2019 Update以降)。
explorer.exe .
 | 2019年8月29日

 | 2019年7月10日

PSoCのプログラマブル論理回路は非常にタイトで、32bitレジスタを複数用意して制御しようとしただけでも許容値を超えてしまいます。そのようなリソース量を節約するための方法として、PSoC内蔵の7bitカウンタモジュールを使うというのがあります。
cy_psoc3_count7 #(.cy_period(7'b111), .cy_route_ld(1), .cy_route_en(1))
DataCounter(
    .clock(clock),
    .reset(1'b0),
    .load(count_reset),
    .enable(1'b1),
    .count(count),
    .tc(data_tc)
);
cy_period周期。カウンターの値がこの値を上回ると、値はリセットされます。
cy_route_ldloadパラメーターを使用するかどうか(1で使用)
cy_route_enenableパラメーターを使用するかどうか
clockカウンターを増やすために使用するクロック
resetカウンターのハードウェアをリセットする
loadカウンターの値をリセットする。resetと違い、カウンター値以外に影響はしない
enableカウンターの有効状態。cy_route_enが0ならこの値は無視される
countここで指定したレジスタに現在のカウンター値が格納される
tcカウンターが一巡した場合に、このレジスタに1が格納される


カウンターを有効にするに当たり注意しておきたいのが、Verilog内だけではなくC言語(CPU)からも有効にさせる命令を実行させなければいけない点です(英語ドキュメントには具体例が言及されているのですが、日本語ドキュメントでは抜け落ちています)。

カウンターを有効にするには「`$INSTANCE_NAME`_[関数で指定した名前]__CONTROL_AUX_CTL_REG」の6ビット目をHighにします。
#define `$INSTANCE_NAME`_enable()  *((reg8*)`$INSTANCE_NAME`_DataCounter__CONTROL_AUX_CTL_REG) |= 0x20
このサンプルでは8カウント目に一巡するとdata_tc値がHighになるので、そのたびにLEDが明滅を繰り返します。また、ボタンとcount_resetは直結されており、ボタンを押している間は常にカウンター値がリセットされるため、その間は全く動いていないように見えます。
`include "cypress.v"

module ctr (
    output  result,
    input   clock,
    input   count_reset
);

wire data_tc;
reg [6:0] count; 
reg result_reg;
 
cy_psoc3_count7 #(.cy_period(7'b111),.cy_route_ld(1),.cy_route_en(1))
DataCounter(
    .clock(clock),
    .reset(1'b0),
    .load(count_reset),
    .enable(1'b1),
    .count(count),
    .tc(data_tc)
);
    
always @(posedge clock)
begin
    if(data_tc)
    begin
        result_reg = ~result_reg;
    end
end

assign result = result_reg;

endmodule
 | 2019年6月28日

カスタムコンポーネントのDMA定義ファイル(*.cydmacap)のLocationタグで「direction="destination"」を指定すると、CPUのメモリー領域からデータパスへのDMAを使った転送が行えるようになります。
<?xml version="1.0" encoding="us-ascii"?>
<DMACapability>
  <Category name="led_out" 
            enabled="true" 
            bytes_in_burst="1"
            bytes_in_burst_is_strict="true" 
            spoke_width="1" 
            inc_addr="false" 
            each_burst_req_request="true">
    <Location name="`$INSTANCE_NAME`_dma_ptr" enabled="true" direction="destination"/>
  </Category>
</DMACapability>
私が調べた限り、データパス(ペリフェラル)への転送は最大16bitまでで、32bitはサポートされていないようなので、ここでは8bit DMAの例を紹介します。
DMA転送ではFIFOバッファを使うことが推奨されています。しかしながら、FIFOバッファからのAレジスタへのコピーで1サイクルが使用されるため、LEDの点滅など非常に低い周期での出力となると、タイミングがずれる原因となります。ここではその解決法の一例として、データパスレジスタを制御する高速なクロックと、GPIOの出力を制御する低速なクロックを分けて実装しています。
`include "cypress.v"

module led_out (
    input   clock,
    input   sync,
    output  led_out,
    output  dma
);

localparam PG_IDLE  = 3'b000;
localparam PG_COPY  = 3'b001;
localparam PG_SHIFT = 3'b010;
localparam PG_WAIT  = 3'b011;

reg[2:0] pg_state;
reg[3:0] bit_count;

wire f0_not_full;
wire f0_is_empty;

reg sync_edge;
reg shift_out;
reg led_out_reg;

always @(posedge clock)
begin
    case(pg_state)
    PG_IDLE:
    begin
        if(~f0_is_empty)
            pg_state <= PG_COPY;
    end
    
    PG_COPY:
    begin
        bit_count <= 4'd0;
        pg_state <= PG_SHIFT;
        sync_edge <= sync;
    end
    
    PG_SHIFT:
    begin
        led_out_reg <= shift_out;
        bit_count <= bit_count + 4'd1;
        pg_state <= (bit_count[3]) ? PG_IDLE : PG_WAIT;
    end
    
    PG_WAIT:
    begin
        if(sync_edge != sync)
        begin
            sync_edge <= sync;
            pg_state <= PG_SHIFT;
        end
    end

    endcase
end

assign led_out = led_out_reg;
assign dma = f0_not_full;

cy_psoc3_dp8 #(.cy_dpconfig_a(
{
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:A0<=F0*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:SHIFT A0*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:*/
    8'hFF, 8'h00,  /*CFG9:*/
    8'hFF, 8'hFF,  /*CFG11-10:*/
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH,
    `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_DEFSI, /*CFG13-12:*/
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0_BUS,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
    `SC_CMP0_NOCHN, /*CFG15-14:*/
    10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO_LEVEL,`SC_FIFO_ASYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:*/
}
)) dp(
    .reset(1'b0),
    .clk(clock),
    .cs_addr(pg_state),
    .route_si(1'b0),
    .route_ci(1'b0),
    .f0_load(1'b0),
    .f1_load(1'b0),
    .d0_load(1'b0),
    .d1_load(1'b0),
    .so(shift_out),
    .f0_bus_stat(f0_not_full),
    .f0_blk_stat(f0_is_empty)
);

endmodule
FIFO入力時において、バッファが満杯でないときは、データパスのf0_bus_stat値がHighになります。そこで、dma出力にこの値を紐付けることで、DMAによる転送が完了したタイミングを伝えています。A0レジスタにコピーしてからは、8bit分シフトアウトを実行し、はみ出した値はGPIOにそのまま出力されます。
DMAウィザードではSourceにメモリー領域であるSRAMを、Destinationには上記のデザイン図のように配置したDMAコンポーネントを指定します。

PSoCではIndexed DMAという手法によって、複数のTDを連結させることができ、待機中のTD領域にデータを書き込んでいくことでダブルバッファとして機能します。「Number of TDs」の値を変更して、複数のDMAデータを設定してみましょう。
各TDには異なるバッファアドレスを与えます。
FIFOバッファに空きが出るごとに配置したInterruptコンポーネントを介して割り込みが発生します。この割り込み関数内でCyDmaChStatusで取得できる値が現在のTDの保有するIDなので、待機中となっているもう片方のバッファに任意のデータをコピーします。
#include "project.h"

uint8_t send_buffer_pos;
uint8_t send_buffer[2][24];
const uint8_t send_buffer_data[] = {
    0b11111111, 0b00000000, 0b11111111, 0b00000000,
    0b11110000, 0b11110000, 0b11110000, 0b11110000,
    0b11001100, 0b11001100, 0b11001100, 0b11001100,
    0b10101010, 0b10101010, 0b10101010, 0b10101010,
    0b11001100, 0b11001100, 0b11001100, 0b11001100,
    0b11110000, 0b11110000, 0b11110000, 0b11110000,
};

/* Defines for led_dma */
#define led_dma_BYTES_PER_BURST 1
#define led_dma_REQUEST_PER_BURST 1
#define led_dma_SRC_BASE (CYDEV_SRAM_BASE)
#define led_dma_DST_BASE (CYDEV_PERIPH_BASE)

/* Variable declarations for led_dma */
/* Move these variable declarations to the top of the function */
uint8 led_dma_Chan;
uint8 led_dma_TD[2];

void InitDma()
{
    /* DMA Configuration for led_dma */
    led_dma_Chan = led_dma_DmaInitialize(led_dma_BYTES_PER_BURST, led_dma_REQUEST_PER_BURST, 
        HI16(led_dma_SRC_BASE), HI16(led_dma_DST_BASE));
    led_dma_TD[0] = CyDmaTdAllocate();
    led_dma_TD[1] = CyDmaTdAllocate();
    CyDmaTdSetConfiguration(led_dma_TD[0], 24, led_dma_TD[1], led_dma__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
    CyDmaTdSetConfiguration(led_dma_TD[1], 24, led_dma_TD[0], led_dma__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
    CyDmaTdSetAddress(led_dma_TD[0], LO16((uint32)send_buffer[0]), LO16((uint32)led_out_dma_ptr));
    CyDmaTdSetAddress(led_dma_TD[1], LO16((uint32)send_buffer[1]), LO16((uint32)led_out_dma_ptr));
    CyDmaChSetInitialTd(led_dma_Chan, led_dma_TD[0]);
    CyDmaChEnable(led_dma_Chan, 1);   
}

void CopyDmaBuffer()
{
    uint8_t cid;
    CyDmaChStatus(led_dma_Chan, &cid, NULL);
    
    uint8_t bpos = (cid == led_dma_TD[1]) ? 0 : 1; 
    memcpy(send_buffer[bpos], send_buffer_data, 24);
}

CY_ISR(OnInterruptLed)
{
    CopyDmaBuffer();
}

int main(void)
{
    CyGlobalIntEnable;
    
    memcpy(send_buffer[0], send_buffer_data, 24);
    memcpy(send_buffer[1], send_buffer_data, 24);
   
    InitDma();
    led_dma_isr_StartEx(OnInterruptLed);

    for(;;)
    {
    }
}
このプログラムでは同じデータを延々と上書きコピーしているだけので、ダブルバッファの意味は薄いのであしからず。
 | 2019年6月21日

前回のシフト挿入の逆を行えば、CPU(C言語)で代入した32bitレジスト値をデータコンポーネントから出力させることができます。

C言語で対象のアドレスに値を代入するとデータコンポーネントの「f0_bus_stat」がHighになります。厳密にはf0_bus_statの4bit全てがHighになっているかを調べる必要がありますが、レジスタへの代入は一度に行われているので、1bitだけのチェックでも問題ありません。

データパスの「A0 WR SRC=F0」によってA0レジスタに値をコピーしてから、左シフトを行うと、各データブロックのはみ出したビットは「cy_psoc3_dp」の「so」パラメータに記録されます。出力された4bitのうち、so[3]が最上位ビットなので、この値を32bit分読み取ると、C言語で入力した32bit値を全て読み取ることになります。
`include "cypress.v"

module sreg_out (
    output  isr,
    output  data,
    input   clock
);

localparam PG_IDLE    = 3'b000;
localparam PG_COPY_F0 = 3'b001;
localparam PG_SHIFTOUT = 3'b010;

reg [2:0] pg_state;
reg [3:0] so_32;
reg [4:0] out_count;
reg f0_empty;
reg f0_not_empty;

always @(posedge clock)
begin
    case(pg_state)
    PG_IDLE:
    begin
        if(f0_not_empty)
        begin
            pg_state = PG_COPY_F0;
        end
    end
    PG_COPY_F0:
    begin
        out_count = 5'd0;
        pg_state = PG_SHIFTOUT;
    end
    PG_SHIFTOUT:
    begin
        out_count = out_count + 5'd1;
        if(out_count == 5'd0)
        begin
            pg_state = PG_IDLE;
        end
    end
    endcase
end

assign isr = f0_empty;
assign data = so_32[3];

cy_psoc3_dp32 #(
.cy_dpconfig_a({
}),
.cy_dpconfig_b({
}),
.cy_dpconfig_c({
}),
.cy_dpconfig_d({
}))dp(
    /*  input              */  .clk(clock),
    /*  input   [02:00]    */  .cs_addr(pg_state),
    /*  input              */  .route_si(1'b0),
    /*  input              */  .route_ci(1'b0),
    /*  input              */  .f0_load(1'b0),
    /*  input              */  .f1_load(1'b0),
    /*  input              */  .d0_load(1'b0),
    /*  input              */  .d1_load(1'b0),
    /*  output  [03:00]    */  .f0_bus_stat(f0_not_empty),
    /*  output  [03:00]    */  .f0_blk_stat(f0_empty),
    /*  output  [03:00]    */  .f1_bus_stat(),
    /*  output  [03:00]    */  .f1_blk_stat(),
    /*  output  [03:00]    */  .so(so_32)
);

endmodule

今回のサンプルでは、32bit分シフトが完了するごとに割り込み信号を発生させ、そのタイミングで新しい値を代入しています。
値がそのままピン出力の状態になるため、LEDの点滅期間が短くなる→長くなるが繰り返されます。
#include "project.h"

int ppos = 0;

const uint32_t patterns[] = {
    0b11111111000000001111111100000000,
    0b11110000111100001111000011110000,
    0b11001100110011001100110011001100,
    0b10101010101010101010101010101010,
    0b11001100110011001100110011001100,
    0b11110000111100001111000011110000,
};

CY_ISR(OnInterruptSO)
{
    sreg_out_SetValue(patterns[ppos]);
    ppos++;
    if(ppos == 6) ppos = 0;
}

int main(void)
{
    CyGlobalIntEnable;

    so_isr_StartEx(OnInterruptSO);

    for(;;)
    {
    }
}
 | 2019年6月19日

PSoCのデータパスは8bitサイズですが、複数のデータパスを連結することで最大32bit幅を持つレジスタを取り扱うことができます。

16bit幅以上を扱うデータパスで、任意の値をレジスタに格納する最も単純な方法は、シフト入力による1bit単位での生成です。このテクニックを身につければ、効率の良さは別にして、様々なデジタル信号をハードウェアレベルで扱えるようになるでしょう。

新規プロジェクトでカスタムコンポーネントを追加し、Verilogファイルを作成し、データパス設定ツールで32bitデータパスを作成します。
設定ツールには「.cy_dpconfig_a」から「.cy_dpconfig_d」までの4つのデータパスが作成されます。まずはこれらを連結しましょう。PSoCの公式ドキュメントでは、データパスを連結するためのモデルケースが提供されています。
この図を参考に「cy_dpconfig_b」と「cy_dpconfig_c」の値をそれぞれ「CI SELB/CI SELA→CHAIN」「CHAIN1/CHAIN0→CHAIN」「CHAIN FB→CHAIN」「CHAIN CMSB→CHAIN」「SI SELB/SI SELA→CHAIN」に、「cy_dpconfig_d」をの値をそれぞれ「CI SELB/CI SELA→CHAIN」「CHAIN1/CHAIN0→CHAIN」「CHAIN FB→CHAIN」「CHAIN CMSB→NOCHN」「SI SELB/SI SELA→CHAIN」に設定します。
32bit値のため、中間ブロックに位置する「UDB_b」の設定は2回適用されていることに気をつけてください。

「SHIFT」の値を「SL」にすると、SRCA(この場合はA0)に対して左シフト演算が行われます。
このとき、シフト演算が行われたSRCAに新しく挿入されるビット値を「SI SELA」で指定できます。「DEFSI」なら「DEF SI」で指定した値(DEF_1なら"1")、「REGIS」なら直前の演算で追い出された(キャリーアウト)値が、「CHAIN」なら連結されているデータパスのビット値になります(つまり、シフトアウトした値が次のデータパスに移動する)。

「ROUTE」を選択するとroute_siの値が適用されるというのが肝です。早い話、シフト演算を実行するときにroute_siに紐付けたレジスタ値を変更すれば、任意の値を生成できるというわけです。

こちらはシフト演算で任意の32bit値を作成するサンプルです。一定周期ごとに1をシフト挿入して、5ビット値のcountがオーバーフローして0になる(=32回)タイミングでFIFO処理を実行させています。
`include "cypress.v"

module shift_reg (
    output  isr,
    input   clock
);

localparam REG_IDLE  = 3'd0;
localparam REG_SHIFT = 3'd1;

reg f0_load_flag;
reg si_value;
reg[4:0] bit_count;
reg[2:0] reg_state;

reg[3:0] step;
reg[4:0] step_count;

always @(posedge clock)
begin
case(reg_state)
    REG_IDLE:
    begin
        f0_load_flag = 1'b0;
        
        step_count = step_count + 1'b1;
        if(step_count == step)
        begin
            si_value = 1'b1;
            step_count = 1'b0;
            step = step + 1'b1;
        end
        else
        begin
            si_value = 1'b0;
        end
        
        reg_state = REG_SHIFT;
    end
    REG_SHIFT:
    begin
        bit_count = bit_count + 5'd1;
        f0_load_flag = (bit_count == 5'd0);
        reg_state = REG_IDLE;
    end
endcase
end

cy_psoc3_dp32 #(
.cy_dpconfig_a({
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:  IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:  SHIFT*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:   */
        8'hFF, 8'h00,    /*CFG9:   */
        8'hFF, 8'hFF,    /*CFG11-10:   */
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH,
    `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_ROUTE, /*CFG13-12:   */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0__A0,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
    `SC_CMP0_NOCHN, /*CFG15-14:   */
        10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:   */
}),
.cy_dpconfig_b({
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:  IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:  SHIFT*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:   */
        8'hFF, 8'h00,    /*CFG9:   */
        8'hFF, 8'hFF,    /*CFG11-10:   */
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_CHAIN,
    `SC_CI_A_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_CHAIN,
    `SC_SI_A_CHAIN, /*CFG13-12:   */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0__A0,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_CHNED,
    `SC_FB_CHNED, `SC_CMP1_CHNED,
    `SC_CMP0_CHNED, /*CFG15-14:   */
        10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO__EDGE,`SC_FIFO_ASYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:   */
}),
.cy_dpconfig_c({
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:  IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:  SHIFT*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:   */
        8'hFF, 8'h00,    /*CFG9:   */
        8'hFF, 8'hFF,    /*CFG11-10:   */
    `SC_CMPB_A0_D1, `SC_CMPA_A1_D1, `SC_CI_B_CHAIN,
    `SC_CI_A_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_CHAIN,
    `SC_SI_A_CHAIN, /*CFG13-12:   */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0__A0,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_CHNED,
    `SC_FB_CHNED, `SC_CMP1_CHNED,
    `SC_CMP0_CHNED, /*CFG15-14:   */
        10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO__EDGE,`SC_FIFO_ASYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:   */
}),
.cy_dpconfig_d({
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:  IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:  SHIFT*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:   */
        8'hFF, 8'h00,    /*CFG9:   */
        8'hFF, 8'hFF,    /*CFG11-10:   */
    `SC_CMPB_A0_D1, `SC_CMPA_A1_D1, `SC_CI_B_CHAIN,
    `SC_CI_A_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_CHAIN,
    `SC_SI_A_CHAIN, /*CFG13-12:   */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0__A0,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_CHNED, `SC_CMP1_CHNED,
    `SC_CMP0_CHNED, /*CFG15-14:   */
        10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO__EDGE,`SC_FIFO_ASYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:   */
}))dp(
    .clk(clock),
    .cs_addr(reg_state),
    .route_si(si_value),
    .route_ci(1'b0),
    .f0_load(f0_load_flag),
    .f1_load(1'b0),
    .d0_load(1'b0),
    .d1_load(1'b0),
    .f0_bus_stat(isr),
    .f0_blk_stat(),
    .f1_bus_stat(),
    .f1_blk_stat()
);

endmodule
なお、対象のレジスタを32bit値として取得するには「CY_GET_REG32」マクロを使います。
#ifndef __`$INSTANCE_NAME`_H__
#define __`$INSTANCE_NAME`_H__

#define `$INSTANCE_NAME`_GetValue() CY_GET_REG32(`$INSTANCE_NAME`_dp_u0__F0_REG)
    
#endif
 | 2019年6月18日

PSoCの標準DMAコンポーネントとやりとりする手段を用意さえすれば、カスタムコンポーネントでDMAによるデータ転送を実装することができます。

標準DMAコンポーネントに自身の仕様を伝えるためには、「DMA Capability」というXMLで構成された宣言ファイルを作成して、コンポーネントに追加する必要があります。このファイルを作成するには、「Add Component Item」より「DMA Capability」を選択します。
<?xml version="1.0" encoding="us-ascii"?>
<DMACapability>
  <Category name="pa_in_fifo" 
            enabled="true" 
            bytes_in_burst="1"
            bytes_in_burst_is_strict="true" 
            spoke_width="1" 
            inc_addr="false" 
            each_burst_req_request="true">
    <Location name="`$INSTANCE_NAME`_DMA_PTR" enabled="true" direction="source"/>
  </Category>
</DMACapability>
内容
Categoryタグパラメーターを格納する。複数記述すれば、DMAコンポーネントで個別の値を適用させることができるようになる。
nameカテゴリーを識別するために使う名称
enabledこのカテゴリーを利用可能にする
bytes_in_burst一度(バースト)に転送するメモリーサイズ(byte単位)
bytes_in_burst_is_strictbytes_in_burstの値を強制し、ユーザーにオプション指定をできないようにさせる。
spoke_widthレジスタのサイズ(byte単位)。例えば標準FFタイマーコンポーネントは16bitサイズなので"2"が適用されている
inc_addr転送ごとにアドレスの値を増やしていくか
each_burst_req_requestバースト転送ごとにDMAの要求を行うか。falseなら初回だけ要求を出し、あとは自動で転送が行われる。
Locationタグ転送元/転送先の定義を記述
name対象のアドレス名。APIヘッダファイルで定義したものを使う。
enabledこのアドレスを使用可能にする
directionアドレスが転送元(Source)か転送先(Destination)か、あるいは両方(Both)か

並列入力のサンプルではレジストが8bitなので、上記コードの値を使用しています。

APIヘッダーではFIFOレジスタのアドレスポインタを取得するマクロを定義します。
#ifndef __`$INSTANCE_NAME`_H__
#define __`$INSTANCE_NAME`_H__

#define `$INSTANCE_NAME`_DMA_PTR ((reg8*)`$INSTANCE_NAME`_dp__F0_REG)
    
#endif
トップデザインの編集ではカスタムコンポーネントとInterruptコンポーネントの間にDMAコンポーネントを挟みます。これにより、DMAコンポーネントによる転送が完了するとNRQ信号が発生し、割り込みが実行されます。
DRQ(DMAリクエスト)端子を表示するにはDMAコンポーネントの「Hardware Request」を「Disable」以外にします。「Hardware Termination」を有効にすると、DMA転送の中止信号を受け取るための端子が表示されます。

「Hardware Request」のオプションには「Derived」「Rising Edge」「Level」の3つがあります。イベントなど不定期に転送が実行される場合は「Rising Edge」を、I2Sのように継続的に転送が実行される場合は「Level」を選択するとよいでしょう。「Derived」はPSoCが最適な接続を選びますが、カスタムコンポーネントでは原則として「Rising Edge」が適用されます。

デザインが完了したら次はC言語の記述といくわけですが、PSoC CreatorにはDMAに特化したコード生成ツールが用意されているので、こちらを積極的に使っていきましょう。
まずは、コードを生成する元になるプロジェクトとDMAコンポーネントを選びます。
続いて転送元と転送先を指定します。自作のコンポーネントがリストに無かったり、「Set Manually」で希望する値を指定できないようであれば、対象の「cydmacap」ファイルが正しい状態にあるかを確認しましょう。
「Number of TDs」の「TD」は「トランザクションディスクリプタ」を意味し、ここに転送情報が格納されます。これを複数個作成し、それぞれを連結することでDMAチェーンを作成し、ダブルバッファのように扱うことができます。

「Loop」を選択すると、転送アドレスが末端に到達すると先頭アドレスへと自動で戻り、転送が続行されます。「Single Chain」であれば、末端に到達すると転送が終了します。

プログラム実行中にどのTDにデータが転送されているかを知るには「CyDmaChStatus」を使用します(第2引数に現在のTD番号が代入される)。

最後に個々のTDの設定を行います。
TD#TDの番号
Endianエンディアンの変換(バイトスワップ)
Enable trqtrq信号の受信による転送中止の許可
Enable nrq転送完了時にnrq信号を送信するかどうか
LengthDMAが転送するバイトサイズ
Source転送元アドレス
Inc転送元アドレスの値を増やしていくかどうか
Destination転送先アドレス
Inc転送先アドレスの値を増やしていくかどうか
Auto Nextプログラムの指示なしに自動で次のTDを実行するか
Next TD次に連結するTDの番号。最後であれば「End」を選択

これでDMAの初期化コードが生成されるので、メインコードにこの文章を貼り付けます。ただし、define文や永続的に使用する変数がごっちゃになっているので、適切に振り分ける必要があります。
/* Defines for pa_in_dma */
#define pa_in_dma_BYTES_PER_BURST 1
#define pa_in_dma_REQUEST_PER_BURST 1
#define pa_in_dma_SRC_BASE (CYDEV_PERIPH_BASE)
#define pa_in_dma_DST_BASE (CYDEV_SRAM_BASE)

/* Variable declarations for pa_in_dma */
/* Move these variable declarations to the top of the function */
uint8 pa_in_dma_Chan;
uint8 pa_in_dma_TD[1];

uint8 res_buffer[32];

void InitDma()
{
    /* DMA Configuration for pa_in_dma */
    pa_in_dma_Chan = pa_in_dma_DmaInitialize(pa_in_dma_BYTES_PER_BURST, pa_in_dma_REQUEST_PER_BURST, 
        HI16(pa_in_dma_SRC_BASE), HI16(pa_in_dma_DST_BASE));
    pa_in_dma_TD[0] = CyDmaTdAllocate();
    CyDmaTdSetConfiguration(pa_in_dma_TD[0], 32, pa_in_dma_TD[0], pa_in_dma__TD_TERMOUT_EN | CY_DMA_TD_INC_DST_ADR);
    CyDmaTdSetAddress(pa_in_dma_TD[0], LO16((uint32)pa_in_DMA_PTR), LO16((uint32)res_buffer));
    CyDmaChSetInitialTd(pa_in_dma_Chan, pa_in_dma_TD[0]);
    CyDmaChEnable(pa_in_dma_Chan, 1);
}
あとはInterruptコンポーネントの初期化関数を追加すれば完成です。表示される内容は以前のサンプルと同じですが、32バイト単位で一度に表示されていきます。
CY_ISR(OnIntrupptPaInDma)
{
    char str[10];
    for(int n = 0; n < 32; n++){
        sprintf(str, "%x ", res_buffer[n]);
        UART_PutString(str);
    }
}

int main(void)
{
    CyGlobalIntEnable;

    isr_dma_StartEx(OnIntrupptPaInDma);
    InitDma();
    
    UART_Start();

    for(;;)
    {
    }
}
 | 2019年6月18日

これまではデータパスのA0レジスタの値を扱ってきましたが、データパスにはFIFOバッファが備わっており、これらに値を蓄積することで滞りないデータの送受信ができます。特に、連続的なメモリー転送を行うDMAを利用するのであればFIFOの実装は不可欠です。並列入力のサンプルを前回に作ったので、これをFIFOバッファに対応させてみましょう。

FIFOを制御するにはF0/F1レジスタを使用します。データパス設定ツールでVerilogファイルを開いたら、「F0 INSEL」の値を「A0」に変更しましょう。これでA0レジスタがF0レジスタにコピーされるようになります。
F0レジスタへの挿入は「f0_load」で指定したレジスタがHighのときに、クロックごとに実行されます。FIFOバッファにデータ存在するとき、「f0_bus_stat」に指定したレジスタの値がHighになるので、これを出力ワイヤに紐付けることで、いつデータを取得すればよいかを知ることができます。
`include "cypress.v"

module pa_in_fifo (
    input   clock,
    output  isr
);

localparam RG_IDLE = 3'b000;
localparam RG_COPY = 3'b001;
reg [2:0]rg_state;

reg[7:0] pa_in_reg;
reg[1:0] val_type;
reg load_fifo;

always @(posedge clock)
begin
case(rg_state)
    RG_IDLE:
    begin
        load_fifo = 1'b0;
        rg_state = RG_COPY;
    end
    
    RG_COPY:
    begin
        case(val_type)
        2'b00:
        begin
            pa_in_reg = 8'b11111111;
        end
        2'b01:
        begin
            pa_in_reg = 8'b11110000;
        end
        2'b10:
        begin
            pa_in_reg = 8'b11001100;
        end
        2'b11:
        begin
            pa_in_reg = 8'b10101010;
        end
        endcase
        val_type = val_type + 1'b1;
        load_fifo = 1'b1;
        rg_state = RG_IDLE;
    end
endcase
end

cy_psoc3_dp #(.cy_dpconfig(
{
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_ENBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:COPY PI to A0*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:*/
    8'hFF, 8'h00,  /*CFG9:*/
    8'hFF, 8'hFF,  /*CFG11-10:*/
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH,
    `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_DEFSI, /*CFG13-12:*/
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, `SC_PI_DYN_EN,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0__A0,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
    `SC_CMP0_NOCHN, /*CFG15-14:*/
    10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:*/
}
)) dp(
    .clk(clock),
    .cs_addr(rg_state),
    .f0_load(load_fifo),
    .f0_bus_stat(isr),
    .pi(pa_in_reg)
);

endmodule
あとは、取得元レジスタをA0からF0に置き換えれば完成です。
#ifndef __`$INSTANCE_NAME`_H__
#define __`$INSTANCE_NAME`_H__

#define `$INSTANCE_NAME`_GetValue() CY_GET_REG8(`$INSTANCE_NAME`_dp__F0_REG)

#endif
#include "project.h"
#include <stdio.h>

CY_ISR(OnIntrupptPaIn)
{
    char str[10];
    sprintf(str, "%x ", pa_in_fifo_GetValue());
    UART_PutString(str);
}

int main(void)
{
    CyGlobalIntEnable;

    isr_dma_StartEx(OnIntrupptPaIn);
    
    UART_Start();

    for(;;)
    {
    }
}
また、並列出力サンプル(7セグドライバー)をFIFOに対応させるには、データパス設定ツールで「A0 WR SRC」の値を「F0」にすれば演算結果をF0レジスタに出力されるので、あとはAPIの参照先レジスタを「CY_SET_REG8(`$INSTANCE_NAME`_dp__F0_REG, v)」と変更するだけです。
`include "cypress.v"

module pa_out (
    input   clock,
    output[7:0] led_out
);

cy_psoc3_dp #(.cy_dpconfig(
{
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0:  */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2:   */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3:           */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4:           */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5:           */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6:           */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7:           */
    8'hFF, 8'h00,  /*CFG9:           */
    8'hFF, 8'hFF,  /*CFG11-10:           */
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH,
    `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_DEFSI, /*CFG13-12:           */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, `SC_PI_DYN_DS,
    1'h0, `SC_FIFO1_BUS, `SC_FIFO0_BUS,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
    `SC_CMP0_NOCHN, /*CFG15-14:           */
    10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16:           */
}
)) dp(
    .clk(clock),
    .cs_addr(3'b000),
    .po(led_out)
);

endmodule

 | 2019年6月17日