前提・実現したいこと
PIC18F14K50のMSSPを利用してEEPROM、AT93C56にデータの書き込み・読み出しを行いたいと考えています。SDIにはSPIを使用し、AT93C56は16ビットモードで使用するものとします。現在、下記回路とソースコードを作成しました。コードはEEPROMの0x05番地に0xF0F0を書き込み、読み出し後、再度0x05番地に0b0101110011011101を書き込み、読み出すことでEEPROMの内容の書き込み・読み出し・上書き動作を確認することを意図したものです。
回路図
図にテキストで示した通り、ORGピンはVccに接続し16ビットモードで動作するようにしております。
該当のソースコード
/* * File: ADCTest.c * Author: FUJITSU * * Created on 2021/03/18, 23:00 */ // PIC18F14K50 Configuration Bit Settings // 'C' source line config statements // CONFIG1L #pragma config CPUDIV = NOCLKDIV #pragma config USBDIV = OFF // CONFIG1H #pragma config FOSC = IRC #pragma config PLLEN = OFF #pragma config PCLKEN = ON #pragma config FCMEN = OFF #pragma config IESO = OFF // CONFIG2L #pragma config PWRTEN = ON #pragma config BOREN = SBORDIS #pragma config BORV = 22 // CONFIG2H #pragma config WDTEN = ON #pragma config WDTPS = 32768 //(10ms~18ms x WDTPS) // CONFIG3H #pragma config HFOFST = OFF #pragma config MCLRE = ON // CONFIG4L #pragma config STVREN = ON #pragma config LVP = OFF #pragma config BBSIZ = OFF #pragma config XINST = OFF // CONFIG5L #pragma config CP0 = OFF #pragma config CP1 = OFF // CONFIG5H #pragma config CPB = OFF #pragma config CPD = OFF // CONFIG6L #pragma config WRT0 = OFF #pragma config WRT1 = OFF // CONFIG6H #pragma config WRTC = OFF #pragma config WRTB = OFF #pragma config WRTD = OFF // CONFIG7L #pragma config EBTR0 = OFF #pragma config EBTR1 = OFF // CONFIG7H #pragma config EBTRB = OFF // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include "AT93C56_AT93C66.h" #define _XTAL_FREQ 4000000 /* * */ void __interrupt() Inter(void){ if(PIR1bits.SSPIF){ PIR1bits.SSPIF = 0; } } void WrenEEPROM(void){ volatile uint8_t Dummy = 0x00; __delay_us(1); //Wait more than 500ns Dummy = SSPBUF; //BF Flag clear EEPROM_CS = 1; //EEPROM select SSPBUF = EEPROM_EWEN; while(!SSPSTATbits.BF){NOP();}; Dummy = SSPBUF; EEPROM_CS = 0; __delay_us(1); //Wait more than 500ns } uint16_t ReadEEPROM(uint8_t address){ //Connect ORG pin of EEPROM to Vcc for 16bit mode volatile uint8_t readData = 0x00; uint16_t returnVal = 0x00; EEPROM_CS = 1; __delay_us(1); readData = SSPBUF; SSPBUF = EEPROM_READ; while(!SSPSTATbits.BF){NOP();}; readData = SSPBUF; SSPBUF = address; while(!SSPSTATbits.BF){NOP();}; readData = SSPBUF; SSPBUF = 0x00; while(!SSPSTATbits.BF){NOP();}; readData = SSPBUF; returnVal = (uint16_t)readData; returnVal = (returnVal << 8); SSPBUF = 0x00; while(!SSPSTATbits.BF){NOP();}; readData = SSPBUF; returnVal |= (uint16_t)readData; EEPROM_CS = 0; __delay_us(1); //Wait more than 500ns return returnVal; } void WriteEEPROM(uint8_t address, uint16_t data){ volatile uint8_t holdData = 0x00; EEPROM_CS = 1; __delay_us(1); holdData = SSPBUF; SSPBUF = EEPROM_WRITE; while(!SSPSTATbits.BF){NOP();}; holdData = SSPBUF; SSPBUF = address; while(!SSPSTATbits.BF){NOP();}; holdData = SSPBUF; holdData = (uint8_t)(data >> 8); SSPBUF = holdData; while(!SSPSTATbits.BF){NOP();}; holdData = SSPBUF; holdData = (uint8_t)(data); SSPBUF = holdData; while(!SSPSTATbits.BF){NOP();}; holdData = SSPBUF; EEPROM_CS = 0; __delay_us(1); } void main(void) { OSCCONbits.IRCF = 0b101; //4MHz OSCCONbits.SCS = 0b11; //Use internal oscillator while(!OSCCONbits.IOFS){NOP(); //SDI Setting //EEPROM/SPI //RB4:SDI //RB5:CS //RB6:CLK //RC7:SDO //MODE0:(CKP = 0),CKE = 1 //立ち上がりで取り込み、立下りで遷移 //MODE1:(CKP = 0),CKE = 0 //立ち上がりで遷移、立下りで取り込み(サンプルコードを見る限り、立下りで取り込みが正解?) //MODE2:(CKP = 1),CKE = 1 //立ち上がりで遷移、立下りで取り込み //MODE3:(CKP = 1),CKE = 0 //立ち上がりで取り込み、立下りで遷移 EEPROM_TRIS = 0; SSPSTATbits.SMP = 0; SSPSTATbits.CKE = 1; TRISCbits.TRISC7 = 0; TRISBbits.TRISB4 = 1; ANSELHbits.ANS10 = 0; TRISBbits.TRISB6 = 0; SSPCON1bits.CKP = 0; SSPCON1bits.SSPM = 0b0001; //Master Mode 0000:/4 0001:/16 0010/64 4us with /16 => 4Mhz SSPCON1bits.SSPEN = 1; //SDI Setting Enable IPR1bits.SSPIP = 1; PIE1bits.SSPIE = 1; uint16_t getByte = 0x0000; WrenEEPROM(); WriteEEPROM(0x05,0xF0F0); getByte = ReadEEPROM(0x05); WriteEEPROM(0x05,0b0101110011011101); getByte = ReadEEPROM(0x05); while(1){ CLRWDT(); } } /* * File: AT93C56_AT93C66.h * Author: FUJITSU * * Created on 2021/03/23, 18:24 */ #ifndef AT93C56_AT93C66_H #define AT93C56_AT93C66_H //Setting IO port #define EEPROM_CS (LATBbits.LB5) #define EEPROM_TRIS (TRISBbits.TRISB5) //utlize of 16bit mode #define EEPROM_READ (0b110) #define EEPROM_ERASE (0b111) #define EEPROM_WRITE (0b101) #define EEPROM_EWEN (0b10011 << 3) #define EEPROM_ERAL (0b100) #define EEPROM_ERAL_SEC (0b10 << 6) #define EEPROM_WRAL (0b100) #define EEPROM_WRAL_SEC (0b01 << 6) #define EEPROM_EWDS (0b100) #define EEPROM_EWDS_SEC (0b00 << 6) #endif /* AT93C56_AT93C66_H */
発生している問題・エラーメッセージ
下図はSDI(黄)とSDO(水)の関係を示したものとなります。
※SDI/SDOはコントローラサイドを基準とします。
次にSDOとCLKの波形を以下の3つに分割して示します。
②1回目の読み出し用空書き込みから2回目の読み出しアドレス指定まで
これらは以下のプロセスをたどっています。
EWENコマンドを送信=>
※以下1回目の読み書き
書き込みコマンドを送信=>
書き込みアドレス(0x05)を送信=>
16ビット書き込みデータ上位8ビット(0xF0)送信=>
16ビット書き込みデータ下位8ビット(0xF0)送信=>
読み出しコマンドを送信=>
読み出しアドレス(0x05)を送信=>
読み出し用ダミーデータを2バイト送信=>
※以下2回目の読み書き
書き込みコマンドを送信=>
書き込みアドレス(0x05)を送信=>
16ビット書き込みデータ上位8ビット(0b01011100)送信=>
16ビット書き込みデータ下位8ビット(0b11011101)送信=>
読み出しコマンドを送信=>
読み出しアドレス(0x05)を送信=>
読み出し用ダミーデータを2バイト送信=>
以上の波形を見ると多少の波形ひずみはあるもののおよそ意図したとおりの動作となっています。
次にSDIとCLKの波形を以下の3つに示します。
④~⑥の波形を見ると読み出しはできていますが出力値はどちらも0x0F75となっており、
①~③の波形で書き込んだ0xF0F0、0x5CDDとは異なった値が出力されています。
また、読み出しアドレスを手付かずのアドレスに指定した場合の読み出し値は0xFFFFとなりました。
以上より読み出し機能自体は正常に動作していると判断します。
これらから書き込み不良がどこかで発生しているものと思いますが、特定できません。
この問題の解法が分かる方は教授願います。
よろしくお願いいたします。
補足情報(FW/ツールのバージョンなど)
現在の出力値0x0F75は以下の経緯で設定されました。以前SDIポートをデジタル入力にしてなかったため入力が常に0x0000となってしまう問題が生じました。そこでいろいろ試行錯誤していた時に適当に設定した値が0x0F75となります。一度、偶然にも値の設定が実施され再現性がない状態となっております。
回答2件
あなたの回答
tips
プレビュー