概要
今回は、dsPIC33AKシリーズのSPIモジュールの動作を確認します。Curiosityボード上には2MByteのQSPIフラッシュメモリが搭載されていますので、読み書きを実装します。
SPIとは「Serial Peripheral Interface」の頭文字をとった用語で、主に基板内でデバイス同士の通信を行う規格です。
関連記事
| 関連記事 | リンク |
| SPIモジュールの使い方 | SPIモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com) |
開発環境
開発環境を以下に示します。
今回はCPUボード(EV02G02A)で動作確認を行います。
| 項目 | 値 | リンク |
| ベースボード | dsPIC33A CURIOSITY PLATFORM DEVELOPMENT BOARD | dsPIC33A Curiosity Platform Development Board User’s Guide (microchip.com) |
| CPUボード(EV68M17A) | EV68M17A – dsPIC33AK128MC106 Motor Control DIM | dsPIC33AK128MC106 Motor Control Dual In-Line Module (DIM) Information Sheet (microchip.com) |
| CPUボード(EV02G02A) | dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | Microchip Technology |
| 統合開発環境 | MPLAB X IDE v6.20 | MPLAB® X IDE | Microchip Technology |
| コンパイラ | MPLAB XC DSC v3.10 | MPLAB® XC DSC Compiler | Microchip Technology |

SPIモジュールについて
ブロック図
下記にSPIモジュールのブロック図を示します。

レジスタ
以下にSPIレジスタとその説明を示します。
| レジスタ名(xは1~3) | 機能 | 説明 |
| SPIxCON1 | SPI制御レジスタ1 | SPIモジュールの設定を行う |
| SPIxCON2 | SPI制御レジスタ2 | 送信ビット長設定 |
| SPIxSTAT | SPIステータスレジスタ | SPIモジュールのステータスレジスタ |
| SPIxBUF | SPIバッファレジスタ | SPI送受信のためのバッファ設定を行う |
| SPIxBRG | SPIボーレートレジスタ | ボーレートの設定を行う |
| SPIxIMSK | SPI割り込みマスクレジスタ | SPI割り込みの要因について設定する |
| SPIxURDT | SPIアンダーランレジスタ | SPIアンダーランデータの設定を行う |
動作説明
ブロック図
今回のブロック図を以下に示します。
本来、RP33ピンにはフラッシュメモリのSCK入力が接続されているため、SCK機能を割り当てる必要があります。しかし、SCKをRP33ピンに割り当てた場合に動作が不安定になる現象が発生しました。RP33ピンにはもともとクロックアウトが割り当てられており、クロックアウトを無効にすれば正常に動作するはずですが、問題は解消されませんでした。
この現象がチップ自体のエラッタによるものなのか、私のCPUボードの故障によるものなのかは不明です。そこで今回は、下図のようにCPUボードのエッジコネクタの76番ピンと83番ピンにテープを貼り、フラッシュメモリとの接続を切断した上で、SCKをRP51ピンに割り当ててベースボード上で接続しました。

ソースコード
コンフィグレーションファイル
コンフィグレーションファイル、クロック設定ファイルは以下のファイルをインクルードしてください。
なおSST26VF020Aのドライバファイルついて、全ての機能の動作確認を行っていません。
■コンフィグレーションファイル
■クロック設定ソースファイル
■クロックヘッダーファイル
■SST26VF020Aソースファイル
■SST26VF020Aヘッダーファイル
ソースコード全体
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clock_driver.h"
#include "FlashMemory_SST26VF_driver.h"
/*----------------------------------------------------------------------------*/
/* 定数定義*/
/*----------------------------------------------------------------------------*/
#define RX_BUFF_SIZE 128
/*----------------------------------------------------------------------------*/
/*変数定義*/
/*----------------------------------------------------------------------------*/
uint32_t ID;
uint8_t FlashBuff[RX_BUFF_SIZE];
static void Uart_Send_Blocking_TX_Data(uint8_t *u1pa_Data);
/*----------------------------------------------------------------------------*/
/**
* @fn main(int argc, char** argv)
* @brief PROJECT_3_1_6_SPI_FLASH
* @param[in] argc argument count
* @param[in] argv argument vector
* @retval EXIT_SUCCESS 成功
* @retval EXIT_FAILURE 失敗
* @detail SPIによるフラッシュメモリアクセス
* @note
*/
/*----------------------------------------------------------------------------*/
int main(int argc, char** argv)
{
/*-----------------------------------------------------------------------*/
/* クロック初期化*/
/*-----------------------------------------------------------------------*/
vdg_Clock_Set_Register();
/*-----------------------------------------------------------------------*/
/* 変数初期化*/
/*-----------------------------------------------------------------------*/
for (int i = 0 ;i<16;i++){FlashBuff[i] = i+2;}
/*-----------------------------------------------------------------------*/
/* ピン設定*/
/*-----------------------------------------------------------------------*/
RPOR12bits.RP50R = 9u; //UART1出力 RP50
RPINR9bits.U1RXR = 52u; //UART1入力 RP52
RPOR10bits.RP44R = 13u; //SDO1
RPOR12bits.RP51R = 14u; //SCK1
RPINR10bits.SDI1R = 60u; //SDI1
TRISDbits.TRISD4 = 0; //SS
//RPOR13bits.RP53R = 15u; //SS1
TRISCbits.TRISC3 = 0; //LED1
TRISCbits.TRISC4 = 0; //LED1
LATDbits.LATD4 = 0u;
/*-----------------------------------------------------------------------*/
/* SPI初期化*/
/*-----------------------------------------------------------------------*/
SPI1CON1 = 0x00000000u;
SPI1CON1bits.ENHBUF = 0u;
SPI1CON1bits.SPIFE = 0u;
SPI1CON1bits.MCLKEN = 0u; //Standard Speed Peripheral Clock
SPI1CON1bits.DISSCK = 0u;
SPI1CON1bits.DISSDI = 0u;
SPI1CON1bits.MSTEN = 1u; //Host mode
SPI1CON1bits.CKP = 0u;
SPI1CON1bits.SSEN = 0u;
SPI1CON1bits.CKE = 1u;
SPI1CON1bits.SMP = 0u;
SPI1CON1bits.MODE16 = 0u;
SPI1CON1bits.MODE32 = 0u;
SPI1CON1bits.DISSDO = 0u;
SPI1CON1bits.SIDL = 0u;
SPI1CON1bits.FRMCNT = 0u;
SPI1CON1bits.FRMSYPW = 0u;
SPI1CON1bits.MSSEN = 0u;
SPI1CON1bits.FRMPOL = 0u;
SPI1CON1bits.FRMSYNC = 0u;
SPI1CON1bits.FRMEN = 0u;
SPI1CON1bits.AUDMOD = 0u;
SPI1CON1bits.URDTEN = 0u;
SPI1CON1bits.AUDMONO = 0u;
SPI1CON1bits.IGNTUR = 0u;
SPI1CON1bits.IGNROV = 0u;
SPI1CON1bits.SPISGNEXT = 0u;
SPI1CON1bits.AUDEN = 0u;
SPI1BRG = 0x00000003u;
SPI1CON1bits.ON = 1u;
// IDの読込
ID = SST26VF_Read_ID();
//ステータス・コンフィグレジスタへの書込み
SST26VF_Write_StatusAndConfig(0,0);
//チップの消去
SST26VF_Erase_Chip();
//ページライト
SST26VF_Write_Page(FlashBuff,0,16);
//バッファクリア
for (int i = 0 ;i<16;i++){FlashBuff[i] = 0;}
//データリード
SST26VF_Read_Data(FlashBuff,0,16);
/*-----------------------------------------------------------------------*/
/*メインルーチン*/
/*-----------------------------------------------------------------------*/
while(1)
{
}
return EXIT_SUCCESS;
}
結果
データリード後のFlashBuffメモリの値を示します。

記事についての注意点
本記事は慎重に内容を検討し正確さに努めておりますが、内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント