PICでSPI SDカードを読み書きする
他のSPIデバイスといっしょに使うとSDカードが読み書きできないというトラブルに見舞われました。なんとか読み書きできるようにはなったのですが....
「SPI接続でSDカードとMCP3208がいっしょに使えない話」
-------
今回の記事はきむしげさん(きむ茶工房ガレージハウス)の記事
「MMC/SDカードを接続し読書きを行って見ます」
に書いてあることを自分でもやってみましたというだけの記事です。自分のメモみたいなものですので実際に自分でもやってみようという方はきむしげさんの記事を読まれた方がいいと思います。きむしげさんの記事は説明が詳しいです。
どうやって入出力をやるのかを基本的なところから自分で確かめて見たいという方にはこちらの方が参考になるかも
「ほよほよのブログ - 初めてのSPI通信、SDカードの読み書き」
「ほよほよのブログ - PCから読める最小限のファイルシステム」
---------
今回もPICはSPIと(LCD表示のための)I2Cが別々に使えるPIC18F26K22でやってみました。このシリーズはPIC18F23K22、PIC18F24K22、PIC18F25K22、PIC18F26K22、PIC18F43K22、PIC18F44K22、PIC18F45K22、PIC18F46K22といくつかありますが同じだと思います。
でやってみた結果なのですが読み書きとも問題なくできました。気になる速度なのですがSPIのクロックが4MHz(のはず)で16バイトのデータを1000回書き込んで十数秒くらいでした。気圧計とか温度計の記録をとるのが目的ですから特に問題なさそうです。多くても毎秒一回数百バイト程度の書き込みができれば十分ですから。
画像は基板にハンダ付けが終わったら追記しておきます。
-----
独自性(?)がちょっとはあるものがやっとできました。
「PIC/I2C大気圧センサーLPS331APの測定値をSDカード(SPI)に記録する - はじめに」
======
PIC PIC18F26K22
コンパイラー Microchip MPLAB XC8 C Compiler (Free Mode) V1.32
表示部分はI2C接続のACM1602を使っています。
じつは同じMSSPモジュールをI2CとSPIに切り替えて使ってみようと思ったのですがまだうまく行っていません。できるのかなあ....
SDカードのソケットは秋月で売っているSDカードスロットDIP化モジュールを使いました。3.3V電源のときはそのまま使え5V電源のときはジャンパー部にはんだをのせます。
なおこのDIP化モジュールは信号線がプルアップしてあるようです。
それと関係あるのかないのかわかりませんが、こんなこともありました。
「SPI接続でトラブル! 複数のデバイスが使えない」
「SPI接続でSDカードとMCP3208がいっしょに使えない話」 (解決編)
SDカードはSanDiskの4GbyteのSDHCのものです。
-------
回路図を書くのが面倒なのでどういう具合に接続されているかだけ書いておきます。
カッコつきの数字はPICkit3のピン番号です。
// 01 /MCLR .....(1)
// 02 RA0/AN0 ====> ソケットの CS
// 03 RA1/AN1 ====> プログラムの制御用
// 14 RC3/SCL1 =====> I2Cバス
// 15 RC4/SDA1 =====> I2Cバス
// 19 VSS .....(3)
// 20 VDD .....(2)
// 22 RB1/INT1/P1C/SCK2/SCL2/C12IN3-/AN10 =====> ソケットの CLK
// 23 RB2/INT2/CTED1/P1B/SDI2/SDA2/AN8 =====> ソケットの SDO
// 24 RB3/CTED2/P2A/CCP2/SDO2/C12IN2-/AN9 =====> ソケットの SDI
// 27 RB6/TX2/PGC .....(5)
// 28 RB7/RX2/PGD .....(4)
------
関連
趣味の電子工作
PIC
「PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き)」
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方」(ソース付き)
「PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装」
--------
ソース
I2CライブラリとAMC1602のライブラリは
「I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして」
にあるものをそのまま使っています。SDカード関連のライブラリはきむしげさんのものを使いましたがほんのちょっとだけ修正して使いました。
main.c
きむしげさんのSD1.cとSD2.cをもとにしたテスト用のプログラムです。いつもどおり“最低限何が必要か”という視点でコーディングしてあります(/MCLRも無効にしていないです)
RA1がGNDに落ちていたら書き込み、RA1をVDDに接続したら読み込みをするように作ってあります。
#include <xc.h> #include <stdio.h>
#include <string.h>
#include "..\..\include\common\MyDef.h"
#include "..\..\include\common\I2CLib.h"
#include "..\..\include\common\ACM1602lib.h"
#include "..\..\include\common\SPILib.h"
#include "..\..\include\common\SDlib.h"
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html
#ifdef _18F26K22
#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF
#endif
void putLCDhex(unsigned char ch)
{
char hex[]="0123456789SBCDEF";
LCD_Putc(hex[ch>>4]) ;
LCD_Putc(hex[ch & 0x0f]) ;
}
void interrupt InterFunction( void )
{
// I2C関連の割り込み処理
InterI2C() ;
}
void main()
{
union {
char c[2] ;
int i ;
} ans ;
char dt_r[32] ;
char dt_w[3][22] = {
"xxxxxxxxxxxxxx\r\n",
"test2\r\n",
"test3\r\n"
} ;
int j;
int row=1;
OSCCON = MyOSCCON ;
// for I2C
ANSELCbits.ANSC3 = 0;
ANSELCbits.ANSC4 = 0;
// for SPI
ANSELBbits.ANSB2 = 0;
ANSELBbits.ANSB1 = 0;
TRISB1 = 0;
TRISB3 = 0;
// OUTPUT /CS
TRISA0 = 0;
PORTAbits.RA0 = 1;
// INPUT
ANSELAbits.ANSA1 = 0;
SPI_Init(SPI_MODE2,SPI_CLOCK_DIV4) ;
InitI2C_Master() ;
LCD_Init() ;
LCD_Clear();
if( PORTAbits.RA1 == 1 ) {
for(j=0; j<100; j++) __delay_ms(30) ; // 3秒後に開始
ans.i = SD_Init() ; // MMC/SDCの初期化を行う
if (ans.i == 0) {
ans.i = SD_Open("XYZ.TXT",O_READ) ; // ファイルのオープン
if (ans.i == 0) {
while(1) {
memset(dt_r,0x00,sizeof(dt_r)) ;
ans.i = SD_fGets(dt_r,18) ; // ファイルから1行読込む
dt_r[strlen(dt_r)-2]=0x00;
if (ans.i != 0) {
LCD_Puts(dt_r) ;
LCD_SetCursor(0,row);
row=1-row;
} else break ;
for(j=0; j<100; j++) __delay_ms(20) ;
}
SD_Close() ; // ファイルのクローズ
if (ans.i == 0) LCD_Puts("Successful End!!") ;
else LCD_Puts("Abnormal Read!!") ;
} else {
LCD_Puts("Error Open!!") ; // オープンエラー
}
} else {
LCD_Puts("Error Init ") ; // 初期化エラー
putLCDhex(ans.c[1]) ;
putLCDhex(ans.c[0]) ;
}
} else {
for(j=0; j<100; j++) __delay_ms(30) ; // 3秒後に開始
// MMC/SDCの初期化を行う
ans.i = SD_Init() ;
if (ans.i == 0) {
// ファイルを新規に作成してオープンする
ans.i = SD_Open("XYZ.TXT",O_RDWR) ;
if (ans.i == 0) {
LCD_Puts("The write start") ;
LCD_SetCursor(0,1);
// ファイルへ1行ずつ書き込む
// for(j=0; j<1000;j++){
// ans.i = SD_Write(dt_w[0],strlen(dt_w[0])) ;
// }
ans.i = SD_Write(dt_w[0],strlen(dt_w[0])) ;
ans.i = SD_Write(dt_w[1],strlen(dt_w[1])) ;
ans.i = SD_Write(dt_w[2],strlen(dt_w[2])) ;
// ファイルのクローズ
SD_Close() ;
if (ans.i != -1) LCD_Puts("Successful End!!") ;
else LCD_Puts("Abnormal Write!!") ;
} else {
LCD_Puts("Error Open!!") ; // オープンエラー
}
} else {
LCD_Puts("Error Init ") ; // 初期化エラー
putLCDhex(ans.c[1]) ;
putLCDhex(ans.c[0]) ;
}
}
while(1) ; // 処理中断
}
SPIlib.h
ここはきむしげさん(きむ茶工房ガレージハウス)のソースと同じですが_XTAL_FREQとCSはMyDef.hの方で設定しています。
#include "..\..\include\common\MyDef.h"
//#ifndef _XTAL_FREQ
// Unless already defined assume 8MHz system frequency
// This definition is required to calibrate __delay_us() and __delay_ms()//#define _XTAL_FREQ 8000000 // 使用するPIC等により動作周波数値を設定する
//#endif
// #define CS RC2 // カード選択信号
SDlib.c
ここもきむしげさん(きむ茶工房ガレージハウス)のソースと同じです。CS(のポート)は事情があってCD_SDとしてMyDef.hで定義してあります。
void cs_select(int flag)
{
CS_SD = flag ;
SPI_transfer(0xff) ; // 確実にCSを切替える為にクロックを送信しておく
}
.
.
.
int SD_Init()
{
unsigned long arg ;
unsigned char r7[4] ;
unsigned int i , ans ;
CS_SD = 1 ;
CardType = 0 ;MyDef.h
/*
* File: MyDef.h
* Author: Seppina
*
* Created on 2014/11/22, 14:38
*/#ifndef MYDEF_H
#define MYDEF_H// http://www.microchip.jp/docs/41406B_JP.pdf
#ifdef _12F1822
#define _XTAL_FREQ 16000000
#define MySSPADD 0x27
#define SSPIE SSP1IE
#define SSPIF SSP1IF
#define BCLIE BCL1IE
#define BCLIF BCL1IF
//#define CS PORTAbits.RA0
#endif// http://ww1.microchip.com/downloads/en/DeviceDoc/40001729A.pdf
// http://ww1.microchip.com/downloads/jp/DeviceDoc/40001722A_JP.pdf
// (下は16F1703のものですが参考になります。これもきむしげさん情報です)
#ifdef _16F1705
#define _XTAL_FREQ 8000000
#define MySSPADD 0x13
#define SSPIE SSP1IE
#define SSPIF SSP1IF
#define BCLIE BCL1IE
#define BCLIF BCL1IF
//#define CS PORTAbits.RA0
#endif// http://ww1.microchip.com/downloads/en/DeviceDoc/40001574C.pdf
#ifdef _16F1938
#define _XTAL_FREQ 8000000
#define MySSPADD 0x13
//#define CS PORTAbits.RA0
#endif// http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf
#ifdef _18F26K22
#define MyOSCCON 0b01110010
#define _XTAL_FREQ 16000000
#define MySSPADD 0x27
#define CS_SD PORTAbits.RA0 // カード選択信号
#endif#endif /* MYDEF_H */
« PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装 | トップページ | バーナード星は動いているか? - 3 - その固有運動と年周視差を測定する »
「趣味の電子工作」カテゴリの記事
- PICで作る100MHz周波数カウンタ検証用XOR(エクスクルーシブオア)逓倍器(2016.03.08)
- 150MHz(~200MHz?)周波数カウンター用プリスケーラー(1/4分周器)(2016.03.06)
- 測温抵抗体(Pt100、白金薄膜温度センサー)の抵抗値を温度に変換する(平方根を使わない)計算式(2016.03.01)
- GPS/JJY(標準電波)を基準周波数源とするためのPLLの詳細(2016.02.27)
- GPS受信モジュール1PPS対決 - GE-612T vs GM-5157A(2016.02.21)
この記事へのコメントは終了しました。
« PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの実装 | トップページ | バーナード星は動いているか? - 3 - その固有運動と年周視差を測定する »
コメント