PSoCデータパスからCPUへ割り込みで並列入力するには

How to parallel input to CPU from PSoC Datapath with interrupt
 
データパスの並列出力は「po」パラメーターの指定だけで実装できましたが、データパスからCPUレジスタに並列でデータを送るには若干の設定が必要です。

データパス設定ツールを起動したら「PI DYN」の箇所を右クリックして表示されるメニューより「Enable Bit」を選択し、このレジスタ値を変更できるようにします。入力できるようになったら、選択肢より「EN」を選びます。これにより、演算処理実行時にA0もしくはA1レジスタにPIに指定した値がコピーされるようになります。
並列入力ができるコンポーネントのサンプルを作成してみます。PSoCプロジェクトを作成してコンポーネントアイテムを追加したら、演算処理のタイミングを制御するためのクロック入力端子と、値が変更されたことをC言語側で検知できるようにするための割り込み信号出力端子を追加します。
ここからVerilogファイルを作成したら、データパス設定ツールでこのファイルを読み込み、「PI DYN」および「Reg1」の値を変更します。
「Reg1」では「CFB_EN」が「ENBL」になっており、これにより、この番号が実行されるときはALUにPIが格納されるようになります。ただし、それだけではCPUレジスタには反映されないので「A0 WR SRC」を「ALU」にしてA0にコピーするように加えて指示します。

このVerilogサンプルでは、クロックごとにcs_addrへの値を切り替え、1番(アドレス1)を実行する時点で割り込み信号をオンにして、C言語側でイベントを受け取るようにしています。
pa_in.v
`include "cypress.v"

module pa_in (
	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 isr_reg;

always @(posedge clock)
begin
case(rg_state)
    RG_IDLE:
    begin
        isr_reg = 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;
        isr_reg = 1'b1;
        rg_state = RG_IDLE;
    end
endcase
end

assign isr = isr_reg;

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_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_EN,
    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(rg_state),
    .pi(pa_in_reg)
);

endmodule
C言語でA0レジスタの値を取得するAPIヘッダー例です。
pa_in_api.h
#ifndef __`$INSTANCE_NAME`_H__
#define __`$INSTANCE_NAME`_H__

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

#endif
メインプログラムの作成に移ります。UART出力の速度に合わせるため、カスタムコンポーネントのクロックソースでは、周波数を指定倍率で分周する「Freq Divider」を介して、「10Hz / 100」という極めて低い周期を与えています。isrには割り込み処理を実装するためのコンポーネントである「System→Interrupt」を接続します。
割り込みをC言語で実装する方法として、「syapicallbacks.h」と「isr_*.c(生成された割り込みコンポーネントのソースファイル)」の「/* Place your Interrupt code here. */」と表記されている箇所にグローバル関数を組み込む方法と、「isr_*_StartEx(生成された割り込みコンポーネントの関数)」にCY_ISRマクロを使ったコールバック関数を指定する方法があります。単純な比較で言えば、StartExを使った割り込みの方がコード量が少なくて済み、扱いやすいと思います。

このプログラムでは割り込みが発生するたびに、UARTへコンポーネントに格納されているA0レジスタの値をバイナリ文字列として表示します。
main.c
#include "project.h"

CY_ISR(OnIntrupptPaIn)
{
    uint8_t v = pa_in_GetValue();
    for(int i = 0; i < 8; i++){
        UART_PutChar((v & 0x80) ? '1' : '0');
        v <<= 1;
    }
}

int main(void)
{
    CyGlobalIntEnable;
    
    isr_pa_in_StartEx(OnIntrupptPaIn);
    UART_Start();

    for(;;)
    {
    }
}
2019/06/17