FC2カウンター FPGAの部屋 PIC16F1825 の使い方4(SPI 機能)
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

PIC16F1825 の使い方4(SPI 機能)

PIC16F1825 の使い方3(I2C 機能、ポーリング編)”の続き。

PIC マイコンの PIC16F1825 を使うことになったので、使い方の覚書を書いておく。
前回は、I2C をポーリングで書き直したが、やはり数分程度で I2C Read が止まってしまった。I2C はあまり良くないかも知れないので、SPI 機能を使うことにした。
3軸加速度センサーの ADXL355 も SPI モードがあるので、 ADXL355 も SPI モードにして使用する。
ADXL355モジュール説明書 によると、 MISO、 ~CS、 SCK、 MOSI の各端子を PIC16F1825 と接続する。
PIC の SPI 接続を示す。

SPI Master : SCLK - RC0(10 pin), SDI - RC1(9 pin), SDO - RC2(8 pin), /CS(GPIO) - RA2(11 pin)

PIC の SDI は ADXL355 の MISO に接続し、 SDO は ADXL355 の MOSI に接続している。後は同じ名前のピンを接続した。なお、PIC の SPI のピン配置はデフォルトの SPI ピンを使用している。

SPI インターフェースについては、”SPIの基本を学ぶ”を参照。
ADXL355日本語説明書の図64 から図67 を引用する。
PIC_15_210324.png

そうそう、PIC の SPI 設定で勘違いしていることがあった。
SPI Read のときに SCK が出ていなかった。てっきり図64 と図66 で R/W を 1 にすれば Read データが出てくるものと思っていたのだが、出てこなかった。なぜ〜? と思ってオシロスコープ画面をよく見たのだが、出ていなかった。もしかして?と思って SSP1BUF にダミーデータとして 0 を書いた(つまり、SDO から 0 を Write した)ところ、SCK が出て SDI に ADXL355 からの Read データが出てきた。つまり、SPI Read する時は、何かダミーデータを SPI Write する必要があるようだ。そうすると SCK が出力されて、SDI に Read データが出てくる。

それを踏まえて、作ったソースコードを貼っておく。

/*
 * File:   acc3_uart.c
 * Author: ono
 *
 * Created on 2021/02/03, 11:09
 */
// USART :  RX - RC5(5 pin), TX - RC4(6 pin)(default)
// SPI Master : SCLK - RC0(10 pin), SDI - RC1(9 pin), SDO - RC2(8 pin), /CS(GPIO) - RA2(11 pin)
// acc_sensor : ADXL355

#include <xc.h>
#include <stdint.h>

#pragma config FOSC = INTOSC
//#pragma config WDTEN = OFF
#pragma config LVP = OFF
#pragma config PWRTE = ON

unsigned char chr;
unsigned int n = 0;

void Delay(unsigned int m)
{
    for(n=0;n<m;n++);       //Delay
}

void acc_sensor_write(uint8_t reg_addr, uint8_t write_data);
void acc_sensor_grecv(uint8_t dataX[3], uint8_t dataY[3], uint8_t dataZ[3]);
uint8_t acc_sensor_data_ready();
uint8_t acc_sensor_read_byte(uint8_t reg_addr);
void acc_sensor_read_3bytes(uint8_t reg_addr, uint8_t *data);

void main( void )
{
    OSCCON = 0b11110000; // 4x PLL enable, 8MHz or 32MHz, FOSC
    //OSCCON = 0b01111000; // 4x PLL disable, 16MHz, FOSC
    OSCTUNE = 0x00;
    
    TRISA = 0;
    TRISC = 0x22; // SDI, UART RX is input setting.
    ANSELA = 0;
    ANSELC = 0;

    // SPI
    SSP1STAT = 0b11000000; // SMP=1, CKE=1
    SSP1CON1 = 0b00100010;  //SSP1EN=1, CKP=0, SPI Master, Clock=Fosc/64(500kHz)
    SSP1CON3 = 0b00000000;
    //SSP1IE = 1;
    //SSP1IF = 0;
    RA2 = 1; // SPI /CS = 1
    
    // UART
    BAUDCON = 0; // BRG16=0: 8bit counter mode
    SPBRGL = 3; // SYNC=0, BRGH=1, BRG16=0, 500000bps
    TXSTA = 0b00100100; // TXEN=1, SYNC=0, BRGH=1
    RCSTA = 0b10010000; // SPEN=1, CREN=1
    //INTCON = 0b11000000; // GIE=1, PEIE=1
    RCIE = 1;
    RCIF = 0;
    PEIE = 1;
    GIE = 1;

     /*while(1){
        while(TRMT == 0);
        TXREG = 0x55;
              
        Delay(50);
    } */
    
    uint8_t dataX[3], dataY[3], dataZ[3];
    uint8_t count=0, count_b;
    
    /*while(1){
        acc_sensor_write(0x2c, 0x83); // I2C speed is Hi speed, +-8g
        Delay(500);
    }*/
    
    acc_sensor_write(0x2c, 0x83); // I2C speed is Hi speed, +-8g
    
    acc_sensor_write(0x1e, 0x00); // OFFSET_X_H
    acc_sensor_write(0x1f, 0x00); // OFFSET_X_L
    acc_sensor_write(0x20, 0x00); // OFFSET_Y_H
    acc_sensor_write(0x21, 0x00); // OFFSET_Y_L
    acc_sensor_write(0x22, 0x00); // OFFSET_Z_H
    acc_sensor_write(0x23, 0x00); // OFFSET_Z_L
    
    acc_sensor_write(0x2d, 0x00); // stanby clear
    
    while(1){
        while((acc_sensor_data_ready() & 0x01) == 0);
        acc_sensor_read_3bytes(0x08, dataX);
        //acc_sensor_grecv(dataX, dataY, dataZ);
        Delay(500);
    }
    
}

void interrupt RX_int(void){
    if(RCIF == 1){
        RCIF = 0;
        chr = RCREG;
        if(RCREG != 0x55)
            return;
              
        while(TRMT == 0);
        TXREG = chr + 1;
    }
}

void acc_sensor_write(uint8_t reg_addr, uint8_t write_data){
    RA2 = 0; // SPI /CS = 0
    SSP1IF = 0;
    SSP1BUF = (reg_addr<<1);
    while(SSP1IF == 0);
    SSP1IF = 0;
    SSP1BUF = write_data;
    while(SSP1IF == 0);
    RA2 = 1; // SPI /CS = 1
}

void acc_sensor_grecv(uint8_t *dataX, uint8_t *dataY, uint8_t *dataZ){
    while((acc_sensor_data_ready() & 0x01) == 0);
    
    acc_sensor_read_3bytes(0x08, dataX);
    acc_sensor_read_3bytes(0x0b, dataY);
    acc_sensor_read_3bytes(0x0e, dataZ);
}

uint8_t acc_sensor_data_ready(){
    return(acc_sensor_read_byte(0x04));
}

uint8_t acc_sensor_read_byte(uint8_t reg_addr){
    uint8_t data;
    
    RA2 = 0; // SPI /CS = 0
    SSP1IF = 0;
    SSP1BUF = (reg_addr<<1) | 1;
    while(SSP1IF == 0);
    
    SSP1IF = 0;
    SSP1BUF = 0;
    while(SSP1IF == 0);
    data = SSP1BUF;
    RA2 = 1; // SPI /CS = 1
    return(data);
}
void acc_sensor_read_3bytes(uint8_t reg_addr, uint8_t *data){
    RA2 = 0; // SPI /CS = 0
    SSP1IF = 0;
    SSP1BUF = (reg_addr<<1) | 1;
    while(SSP1IF == 0);
    
    SSP1IF = 0;
    SSP1BUF = 0;
    while(SSP1IF == 0);
    data[0] = SSP1BUF;
    
    SSP1IF = 0;
    SSP1BUF = 0;
    while(SSP1IF == 0);
    data[1] = SSP1BUF;
    
    SSP1IF = 0;
    SSP1BUF = 0;
    while(SSP1IF == 0);
    data[2] = SSP1BUF;
    RA2 = 1; // SPI /CS = 1
}


SPI クロックは 32 MHz クロックの 1/64 倍の 500 kHz に設定してある。

これで data_ready の値を取得するために、1バイト Read してから、3 バイト Read している波形を示す。
最初に SCK と SDO の波形を示す。
PIC_9_210323.jpg
PIC_10_210323.jpg
PIC_11_210323.jpg
7 ビットの 0x04アドレスと R/W ビットを連結して ADXL355 に Write して、次に Read データを受け取っている。次に 0x08 アドレスの Read を行って、3 バイト X 軸加速度値を Read している。

次に同じアクセスの SCK と SDI の波形を示す。こちらが ADXL355 からの X 軸加速度値だ。
PIC_12_210323.jpg
PIC_13_210323.jpg
PIC_14_210323.jpg

0x04アドレスの値は 0x07 で data ready ビットは立っていたので、3 バイト X 軸加速度値を Read して、その値は、0xFF、 0xF6、 0xA0 だった。つまり、0xFFF6A が X 軸加速度値となる。
  1. 2021年03月24日 04:31 |
  2. PIC
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/5186-64d52803
この記事にトラックバックする(FC2ブログユーザー)