parent
e555d1e3cf
commit
0ebe9c4fd7
@ -0,0 +1,546 @@ |
||||
#include "Bakalarka.h" |
||||
|
||||
#include "prescaler.h" |
||||
#include <stdio.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <avr/eeprom.h> |
||||
//#include <avr/wdt.h>
|
||||
|
||||
|
||||
#include "rotary.h" |
||||
Rotary encoder = Rotary(ENC_A, ENC_B); |
||||
|
||||
#include "DS1302/DS1302.h" |
||||
DS1302 rtc(DS_RST, DS_IO, DS_SCK); |
||||
|
||||
#include "SPI/SPI.h" |
||||
#include "MFRC522/MFRC522.h" |
||||
MFRC522 mfrc522(RFID_SS, RFID_RST); |
||||
|
||||
#include "PCD8544/PCD8544.h" |
||||
PCD8544 lcd(LCD_DC, LCD_RST, LCD_SS); |
||||
|
||||
#include <Fat16.h> |
||||
#include <Fat16util.h> |
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s)) |
||||
SdCard card; |
||||
Fat16 file; |
||||
|
||||
#include "SerialCommand/SerialCommand.h" |
||||
SerialCommand SCmd; |
||||
|
||||
|
||||
|
||||
volatile uint32_t lastDebounce; |
||||
volatile int8_t currentMenuItem = 0; |
||||
volatile boolean button = false, cursor = false, reading = false; |
||||
uint16_t lastRefresh; |
||||
static uint8_t storageIndex EEMEM; |
||||
|
||||
|
||||
|
||||
Menu storage = {"Storage", list, 0}; |
||||
Menu add_storage = {"New file", addStorage, 0}; |
||||
Menu date_time = {"Date/time", frontPage, 0}; |
||||
Menu exit_menu = {"Exit", frontPage, 0}; |
||||
//Menu s1 = {"s1", list, 0};
|
||||
//Menu s2 = {"s2", list, 0};
|
||||
//Menu s3 = {"s3", list, 0};
|
||||
//Menu s4 = {"s4", list, 0};
|
||||
|
||||
Menu mainMenu = { "", NULL, 4, { &storage, &add_storage, &date_time, &exit_menu} }; |
||||
|
||||
|
||||
// bitmaps
|
||||
const byte icon_usb[20] PROGMEM = { |
||||
0x08, 0x1C, 0x3E, 0x3E, 0x1C, 0x08, 0x0C, 0x0E, 0x0A, 0x1A, |
||||
0x3B, 0x6B, 0x4B, 0xE8, 0xE8, 0xE8, 0x08, 0x3E, 0x1C, 0x08 |
||||
}; |
||||
|
||||
const byte icon_battery_100[21] PROGMEM = { |
||||
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, |
||||
0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xFF, 0x3C, 0x3C |
||||
}; |
||||
|
||||
const byte icon_battery_75[21] PROGMEM = { |
||||
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, |
||||
0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C |
||||
}; |
||||
|
||||
const byte icon_battery_50[21] PROGMEM = { |
||||
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, |
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C |
||||
}; |
||||
|
||||
const byte icon_battery_25[21] PROGMEM = { |
||||
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, |
||||
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C |
||||
}; |
||||
|
||||
const byte icon_arrow[6] PROGMEM = { |
||||
0x00, 0xFE, 0x7C, 0x38, 0x10, 0x00 |
||||
}; |
||||
|
||||
void setup(void) { |
||||
// There is 16HMz crystal used, halve it to reliable 8MHz@3V3
|
||||
setClockPrescaler(CLOCK_PRESCALER_2); |
||||
|
||||
// The fastest reliable baud rate is 38400
|
||||
Serial.begin(38400); |
||||
|
||||
lcd.begin(); |
||||
lcd.clear(); |
||||
|
||||
// Rotary interrupt pin change enable
|
||||
PCICR |= (1 << PCIE1); |
||||
PCMSK1 |= (1 << PCINT8) | (1 << PCINT9); |
||||
|
||||
// RFID host interrupt request
|
||||
attachInterrupt(0, RFIDInterrupt, FALLING); |
||||
// Encoder button interrupt handle
|
||||
attachInterrupt(1, debounceInterrupt, FALLING); |
||||
// Encoder button pull-up
|
||||
pinMode(BTN, INPUT_PULLUP); |
||||
|
||||
|
||||
SPI.begin(); // Init SPI bus
|
||||
mfrc522.PCD_Init(); // Init MFRC522 card
|
||||
|
||||
if (!card.init(0, SD_SS)) |
||||
error("card.init failed!"); |
||||
|
||||
if (!Fat16::init(&card)) |
||||
error("Fat16::init failed!"); |
||||
|
||||
pinMode(SPKR, OUTPUT); |
||||
pinMode(VBAT_ADC_EN, OUTPUT); |
||||
|
||||
// wdt_enable(WDTO_8S);
|
||||
|
||||
frontPage(); |
||||
|
||||
SCmd.addCommand("ls", ls); |
||||
SCmd.addCommand("touch", touch); |
||||
SCmd.addCommand("rm", rm); |
||||
// SCmd.addCommand("HELLO", SayHello); // Echos the string argument back
|
||||
// SCmd.addCommand("P", process_command); // Converts two arguments to integers and echos them back
|
||||
SCmd.addDefaultHandler(unrecognized); // Handler for command that isn't matched (says "What?")
|
||||
|
||||
sei(); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
void loop(void) { |
||||
// wdt_reset();
|
||||
// tone(SPKR, 1000, 100);
|
||||
// topBar();
|
||||
SCmd.readSerial(); |
||||
|
||||
if (millis() - lastRefresh > 1000) { |
||||
frontPage(); |
||||
lastRefresh = millis(); |
||||
} |
||||
|
||||
|
||||
if (button) { |
||||
button = false; |
||||
navigateMenu(&mainMenu); |
||||
return; |
||||
// uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]);
|
||||
// if (currentMenuItem >= menuLenght)
|
||||
// currentMenuItem = 0;
|
||||
// else if (currentMenuItem < 0)
|
||||
// currentMenuItem = menuLenght - 1;
|
||||
// lcd.setCursor(0, 0);
|
||||
// uint8_t i = 0, offset = 0;
|
||||
// if (currentMenuItem >= PCD8544_LINES)
|
||||
// offset = currentMenuItem - PCD8544_LINES + 1;
|
||||
// for (i = offset; i < menuLenght && i < PCD8544_LINES + offset; i++) {
|
||||
// if (i == (uint8_t)currentMenuItem)
|
||||
// lcd.bitmap(icon_arrow, 1, 6);
|
||||
// else
|
||||
// lcd.print(' ');
|
||||
// lcd.print(menuItems[i]);
|
||||
// lcd.clearRestOfLine();
|
||||
// }
|
||||
|
||||
} |
||||
|
||||
|
||||
// delay(1000);
|
||||
// lcd.clear();
|
||||
|
||||
// topBar();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// delay(1000);
|
||||
|
||||
// if (Serial.available()) {
|
||||
// Fat16::ls(LS_DATE | LS_SIZE);
|
||||
// while(Serial.available())
|
||||
// Serial.read();
|
||||
// }
|
||||
|
||||
if (reading && mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { |
||||
// // Look for new cards
|
||||
// if ( ! mfrc522.PICC_IsNewCardPresent())
|
||||
// return;
|
||||
//
|
||||
//
|
||||
// // Select one of the cards
|
||||
// if ( ! mfrc522.PICC_ReadCardSerial())
|
||||
// return;
|
||||
|
||||
tone(SPKR, 5500, 70); |
||||
|
||||
delay(1500); |
||||
reading = false; |
||||
|
||||
if (file.open(eeprom_read_byte(&storageIndex), O_APPEND | O_WRITE)) { |
||||
Time t = rtc.time(); |
||||
char buf[21]; |
||||
snprintf(buf, sizeof buf, "%04d-%02d-%02d %02d:%02d:%02d;", t.yr, t.mon, t.day, t.hr, t.min, t.sec); |
||||
file.print(buf); |
||||
for (byte i = 0; i < mfrc522.uid.size; i++) { |
||||
file.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : ""); |
||||
file.print(mfrc522.uid.uidByte[i], HEX); |
||||
} |
||||
file.println(";"); |
||||
file.close(); |
||||
} |
||||
|
||||
// lcd.setCursor(0, 1);
|
||||
// for (byte i = 0; i < mfrc522.uid.size; i++) {
|
||||
// lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
|
||||
// lcd.print(mfrc522.uid.uidByte[i], HEX);
|
||||
// }
|
||||
// lcd.clearRestOfLine();
|
||||
//// Dump debug info about the card. PICC_HaltA() is automatically called.
|
||||
// mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
|
||||
} |
||||
|
||||
delay(100); |
||||
|
||||
} |
||||
|
||||
ISR(PCINT1_vect) { |
||||
cursor = encoder.process(); |
||||
if (cursor == DIR_CW) |
||||
currentMenuItem++; |
||||
else if (cursor == DIR_CCW) |
||||
currentMenuItem--; |
||||
|
||||
} |
||||
|
||||
void debounceInterrupt(void) { |
||||
if ((long) (micros() - lastDebounce) >= (long)DEBOUNCE * 1000) { |
||||
button = true; |
||||
lastDebounce = micros(); |
||||
} |
||||
} |
||||
|
||||
void RFIDInterrupt(void) { |
||||
if (!reading) |
||||
reading = true; |
||||
} |
||||
|
||||
void error_P(const char* str) { |
||||
lcd.setCursor(1, 4); |
||||
lcd.print(PSTR("ERROR")); |
||||
PgmPrint("error: "); |
||||
SerialPrintln_P(str); |
||||
if (card.errorCode) { |
||||
PgmPrint("SD error: "); |
||||
Serial.println(card.errorCode, HEX); |
||||
} |
||||
while (1) |
||||
; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
void navigateMenu(Menu *menu) { |
||||
if (menu->numSubmenus == 0) { |
||||
/* Execute the command */ |
||||
lcd.clear(); |
||||
menu->command(); |
||||
return; |
||||
} |
||||
/* This is a menu, not a command, so show the menu and get the user's choice */ |
||||
displayMenu(menu); |
||||
if (button) { |
||||
button = false; |
||||
menu = menu->submenu[currentMenuItem]; |
||||
} |
||||
// menu = get_user_selection(menu);
|
||||
navigateMenu(menu); |
||||
} |
||||
|
||||
void displayMenu(Menu *menu) { |
||||
// uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]);
|
||||
if (currentMenuItem >= menu->numSubmenus) |
||||
currentMenuItem = 0; |
||||
else if (currentMenuItem < 0) |
||||
currentMenuItem = menu->numSubmenus - 1; |
||||
lcd.setCursor(0, 0); |
||||
uint8_t i = 0, offset = 0; |
||||
if (currentMenuItem >= PCD8544_LINES) |
||||
offset = currentMenuItem - PCD8544_LINES + 1; |
||||
for (i = offset; i < PCD8544_LINES + offset; i++) { |
||||
// clear rest of the menu screen if there are less items than LCD lines
|
||||
if (i >= menu->numSubmenus) { |
||||
lcd.print(' '); |
||||
lcd.clearRestOfLine(); |
||||
continue; |
||||
} |
||||
|
||||
if (i == (uint8_t)currentMenuItem) |
||||
lcd.bitmap(icon_arrow, 1, 6); |
||||
else |
||||
lcd.print(' '); |
||||
lcd.print(menu->submenu[i]->title); |
||||
lcd.clearRestOfLine(); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
void list(void) { |
||||
cursor = DIR_CW; |
||||
while (!button) { |
||||
if (cursor) { |
||||
lcd.setCursor(0, 0); |
||||
dir_t d; |
||||
uint16_t i = 0; |
||||
boolean found = false; |
||||
uint8_t offset = 0; |
||||
if (currentMenuItem >= PCD8544_LINES) |
||||
offset = currentMenuItem - PCD8544_LINES + 1; |
||||
for (i = offset; Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID); i++) { |
||||
// if we are over the display, just seek the last file index
|
||||
if (i >= (uint16_t)(PCD8544_LINES + offset)) |
||||
continue; |
||||
if (i == (uint16_t) currentMenuItem) { |
||||
lcd.bitmap(icon_arrow, 1, 6); |
||||
found = true; |
||||
} |
||||
else |
||||
lcd.print(' '); |
||||
|
||||
lcd.print(i); |
||||
lcd.print(':'); |
||||
printDirName(d); |
||||
} |
||||
|
||||
Serial.print("a: "); |
||||
if (!found) { |
||||
Serial.print("NOTfound, "); |
||||
if (cursor == DIR_CW) { |
||||
currentMenuItem++; |
||||
Serial.print("++"); |
||||
} else if (cursor == DIR_CCW) { |
||||
currentMenuItem--; |
||||
Serial.print("--"); |
||||
} |
||||
} |
||||
else |
||||
// this means that the screen will be refreshed
|
||||
cursor = false; |
||||
|
||||
|
||||
if (currentMenuItem < 0) { |
||||
currentMenuItem = i - 1; |
||||
cursor = DIR_CCW; |
||||
Serial.print("i-1"); |
||||
} |
||||
if ((uint16_t) currentMenuItem > i - 1) { |
||||
currentMenuItem = 0; |
||||
Serial.print("0"); |
||||
cursor = DIR_CW; |
||||
} |
||||
|
||||
Serial.print("; cmi: "); |
||||
Serial.print(currentMenuItem); |
||||
Serial.print(", li: "); |
||||
Serial.print(i); |
||||
Serial.print(", cursor: "); |
||||
Serial.print(cursor); |
||||
Serial.print(", button: "); |
||||
Serial.println(button); |
||||
|
||||
} |
||||
} |
||||
|
||||
Serial.println("Saved"); |
||||
|
||||
// save index of a file to store into to the EEPROM memory
|
||||
eeprom_write_byte(&storageIndex, currentMenuItem); |
||||
button = false; |
||||
lcd.clear(); |
||||
frontPage(); |
||||
} |
||||
|
||||
|
||||
void addStorage(void) { |
||||
// file.writeError = false;
|
||||
char buf[14]; |
||||
for (unsigned short int i = 1; ; i++) { |
||||
snprintf(buf, sizeof buf, "file%d.csv", i); |
||||
if (file.open(buf, O_CREAT | O_WRITE | O_EXCL)) |
||||
break; |
||||
} |
||||
file.close(); |
||||
frontPage(); |
||||
// snprintf(buf, sizeof buf, "FILE%d.CSV", 1);
|
||||
|
||||
} |
||||
|
||||
|
||||
void frontPage(void) { |
||||
|
||||
// lcd.clear();
|
||||
lcd.setCursor(0, 0); |
||||
// tone(SPKR, 5000, 50);
|
||||
// USB plugged in
|
||||
if (analogRead(STAT) < 512) { |
||||
lcd.bitmap(icon_usb, 1, 20); |
||||
} |
||||
// battery
|
||||
else { |
||||
digitalWrite(VBAT_ADC_EN, LOW); |
||||
uint8_t vbat = (analogRead(VBAT_ADC) - 523) / 5; |
||||
if (vbat < 25) |
||||
lcd.bitmap(icon_battery_25, 1, 21); |
||||
else if (vbat < 50) |
||||
lcd.bitmap(icon_battery_50, 1, 21); |
||||
else if (vbat < 75) |
||||
lcd.bitmap(icon_battery_75, 1, 21); |
||||
else |
||||
lcd.bitmap(icon_battery_100, 1, 21); |
||||
digitalWrite(VBAT_ADC_EN, HIGH); |
||||
|
||||
} |
||||
|
||||
// Get the current time and date from the chip.
|
||||
Time t = rtc.time(); |
||||
|
||||
char buf[24]; |
||||
lcd.setCursor(9, 0); |
||||
snprintf(buf, sizeof(buf), "%02d:%02d", t.hr, t.min); |
||||
lcd.print(buf); |
||||
|
||||
uint16_t i = eeprom_read_byte(&storageIndex); |
||||
dir_t d; |
||||
if (Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID)) { |
||||
lcd.setCursor(0, 2); |
||||
lcd.println("Saving to: "); |
||||
printDirName(d); |
||||
} |
||||
|
||||
} |
||||
|
||||
void printDirName(const dir_t& dir) { |
||||
uint8_t w = 0; |
||||
for (uint8_t i = 0; i < 11; i++) { |
||||
if (dir.name[i] == ' ') |
||||
continue; |
||||
if (i == 8) { |
||||
lcd.print('.'); |
||||
w++; |
||||
} |
||||
lcd.print((char) dir.name[i]); |
||||
w++; |
||||
} |
||||
lcd.clearRestOfLine(); |
||||
} |
||||
//
|
||||
//void SayHello() {
|
||||
// char *arg;
|
||||
// arg = SCmd.next(); // Get the next argument from the SerialCommand object buffer
|
||||
// if (arg != NULL) // As long as it existed, take it
|
||||
// {
|
||||
// Serial.print("Hello ");
|
||||
// Serial.println(arg);
|
||||
// } else {
|
||||
// Serial.println("Hello, whoever you are");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void process_command() {
|
||||
// int aNumber;
|
||||
// char *arg;
|
||||
//
|
||||
// Serial.println("We're in process_command");
|
||||
// arg = SCmd.next();
|
||||
// if (arg != NULL) {
|
||||
// aNumber = atoi(arg); // Converts a char string to an integer
|
||||
// Serial.print("First argument was: ");
|
||||
// Serial.println(aNumber);
|
||||
// } else {
|
||||
// Serial.println("No arguments");
|
||||
// }
|
||||
//
|
||||
// arg = SCmd.next();
|
||||
// if (arg != NULL) {
|
||||
// aNumber = atol(arg);
|
||||
// Serial.print("Second argument was: ");
|
||||
// Serial.println(aNumber);
|
||||
// } else {
|
||||
// Serial.println("No second argument");
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
|
||||
void ls() { |
||||
Fat16::ls(); |
||||
} |
||||
|
||||
void touch() { |
||||
char *arg, fileName[14]; |
||||
arg = SCmd.next(); |
||||
snprintf(fileName, sizeof fileName, "%s.csv", arg); |
||||
PgmPrint("File '"); |
||||
Serial.print(fileName); |
||||
if (!file.open(fileName, O_CREAT | O_WRITE)) |
||||
PgmPrintln("' could not be created."); |
||||
else |
||||
PgmPrintln("' was created successfully"); |
||||
|
||||
} |
||||
|
||||
void rm() { |
||||
char *arg, fileName[14]; |
||||
arg = SCmd.next(); |
||||
snprintf(fileName, sizeof fileName, "%s.csv", arg); |
||||
PgmPrint("File '"); |
||||
Serial.print(fileName); |
||||
if (file.open(fileName, O_WRITE) && file.remove()) |
||||
PgmPrintln("' was removed successfully"); |
||||
else |
||||
PgmPrintln("' could not be removed."); |
||||
|
||||
} |
||||
|
||||
void mv() { |
||||
char *arg; |
||||
} |
||||
|
||||
|
||||
// This gets set as the default handler, and gets called when no other command matches.
|
||||
void unrecognized() { |
||||
PgmPrintln("Unrecognized command. Possibilities are: "); |
||||
PgmPrintln("ls\t\t\t- display files"); |
||||
PgmPrintln("touch FILE\t\t- create file FILE.csv"); |
||||
Serial.println(); |
||||
} |
@ -0,0 +1,88 @@ |
||||
// Only modify this file to include
|
||||
// - function definitions (prototypes)
|
||||
// - include files
|
||||
// - extern variable definitions
|
||||
// In the appropriate section
|
||||
|
||||
#ifndef Bakalarka_H_ |
||||
#define Bakalarka_H_ |
||||
#include "Arduino.h" |
||||
//add your includes for the project Bakalarka here
|
||||
#include "PCD8544/PCD8544.h" |
||||
#include <Fat16.h> |
||||
|
||||
//end of add your includes here
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
void loop(); |
||||
void setup(); |
||||
#ifdef __cplusplus |
||||
} // extern "C"
|
||||
#endif |
||||
|
||||
//add your function definitions for the project Bakalarka here
|
||||
|
||||
|
||||
// pins on ATmega328
|
||||
#define RFID_IRQ 2 |
||||
#define BTN 3 |
||||
#define RFID_RST 4 |
||||
#define DS_SCK 5 |
||||
#define DS_IO 6 |
||||
#define DS_RST 7 |
||||
#define LCD_SS 8 |
||||
#define SD_SS 9 |
||||
#define RFID_SS 10 |
||||
#define ENC_A A0 |
||||
#define ENC_B A1 |
||||
#define LCD_DC A2 |
||||
#define LCD_RST A3 |
||||
#define SPKR A4 |
||||
#define VBAT_ADC_EN A5 |
||||
#define VBAT_ADC A6 |
||||
#define STAT A7 |
||||
|
||||
// config
|
||||
#define DEBOUNCE 200 |
||||
|
||||
// function macros
|
||||
//#define error(s) error_P(PSTR(s)) // store error strings in flash to save RAM
|
||||
|
||||
|
||||
|
||||
#define MAX_SUBMENUS 4 |
||||
|
||||
typedef struct menu { |
||||
const char title[PCD8544_COLS]; |
||||
void (*command)(); |
||||
uint8_t numSubmenus; |
||||
struct menu *submenu[MAX_SUBMENUS]; |
||||
} Menu; |
||||
|
||||
// prototypes
|
||||
void debounceInterrupt(void); |
||||
void RFIDInterrupt(void); |
||||
|
||||
void error_P(const char* str); |
||||
|
||||
void frontPage(void); |
||||
void list(void); |
||||
void navigateMenu(Menu *menu); |
||||
void displayMenu(Menu *menu); |
||||
void addStorage(void); |
||||
void printDirName(const dir_t& dir); |
||||
|
||||
//void SayHello(void);
|
||||
//void process_command(void);
|
||||
void ls(void); |
||||
void touch(void); |
||||
void rm(void); |
||||
void unrecognized(void); |
||||
|
||||
|
||||
//Do not add code below this line
|
||||
#endif /* Bakalarka_H_ */ |
||||
|
||||
|
||||
|
@ -0,0 +1,202 @@ |
||||
|
||||
#include "Arduino.h" |
||||
|
||||
#include "DS1302.h" |
||||
|
||||
Time::Time(const uint16_t yr, const uint8_t mon, const uint8_t date, |
||||
const uint8_t hr, const uint8_t min, const uint8_t sec, |
||||
const Day day) { |
||||
this->yr = yr; |
||||
this->mon = mon; |
||||
this->date = date; |
||||
this->hr = hr; |
||||
this->min = min; |
||||
this->sec = sec; |
||||
this->day = day; |
||||
} |
||||
|
||||
|
||||
DS1302::DS1302(const uint8_t ce_pin, const uint8_t io_pin, |
||||
const uint8_t sclk_pin) { |
||||
ce_pin_ = ce_pin; |
||||
io_pin_ = io_pin; |
||||
sclk_pin_ = sclk_pin; |
||||
|
||||
pinMode(ce_pin, OUTPUT); |
||||
pinMode(sclk_pin, OUTPUT); |
||||
} |
||||
|
||||
void DS1302::writeOut(const uint8_t value) { |
||||
pinMode(io_pin_, OUTPUT); |
||||
shiftOut(io_pin_, sclk_pin_, LSBFIRST, value); |
||||
} |
||||
|
||||
uint8_t DS1302::readIn() { |
||||
uint8_t input_value = 0; |
||||
uint8_t bit = 0; |
||||
pinMode(io_pin_, INPUT); |
||||
|
||||
for (int i = 0; i < 8; ++i) { |
||||
bit = digitalRead(io_pin_); |
||||
input_value |= (bit << i); |
||||
|
||||
digitalWrite(sclk_pin_, HIGH); |
||||
delayMicroseconds(1); |
||||
digitalWrite(sclk_pin_, LOW); |
||||
} |
||||
|
||||
return input_value; |
||||
} |
||||
|
||||
uint8_t DS1302::registerBcdToDec(const Register reg, const uint8_t high_bit) { |
||||
const uint8_t mask = (1 << (high_bit + 1)) - 1; |
||||
uint8_t val = readRegister(reg); |
||||
val &= mask; |
||||
val = (val & 15) + 10 * ((val & (15 << 4)) >> 4); |
||||
return val; |
||||
} |
||||
|
||||
uint8_t DS1302::registerBcdToDec(const Register reg) { |
||||
return registerBcdToDec(reg, 7); |
||||
} |
||||
|
||||
void DS1302::registerDecToBcd(const Register reg, uint8_t value, |
||||
const uint8_t high_bit) { |
||||
const uint8_t mask = (1 << (high_bit + 1)) - 1; |
||||
uint8_t regv = readRegister(reg); |
||||
|
||||
// Convert value to bcd in place.
|
||||
uint8_t tvalue = value / 10; |
||||
value = value % 10; |
||||
value |= (tvalue << 4); |
||||
|
||||
// Replace high bits of value if needed.
|
||||
value &= mask; |
||||
value |= (regv &= ~mask); |
||||
|
||||
writeRegister(reg, value); |
||||
} |
||||
|
||||
void DS1302::registerDecToBcd(const Register reg, const uint8_t value) { |
||||
registerDecToBcd(reg, value, 7); |
||||
} |
||||
|
||||
uint8_t DS1302::readRegister(const Register reg) { |
||||
uint8_t cmd_byte = 129; // 1000 0001
|
||||
uint8_t reg_value; |
||||
cmd_byte |= (reg << 1); |
||||
|
||||
digitalWrite(sclk_pin_, LOW); |
||||
digitalWrite(ce_pin_, HIGH); |
||||
|
||||
writeOut(cmd_byte); |
||||
reg_value = readIn(); |
||||
|
||||
digitalWrite(ce_pin_, LOW); |
||||
|
||||
return reg_value; |
||||
} |
||||
|
||||
void DS1302::writeRegister(const Register reg, const uint8_t value) { |
||||
uint8_t cmd_byte = (128 | (reg << 1)); |
||||
|
||||
digitalWrite(sclk_pin_, LOW); |
||||
digitalWrite(ce_pin_, HIGH); |
||||
|
||||
writeOut(cmd_byte); |
||||
writeOut(value); |
||||
|
||||
digitalWrite(ce_pin_, LOW); |
||||
} |
||||
|
||||
void DS1302::writeProtect(const bool enable) { |
||||
writeRegister(kWriteProtectReg, (enable << 7)); |
||||
} |
||||
|
||||
void DS1302::halt(const bool enable) { |
||||
uint8_t sec = readRegister(kSecondReg); |
||||
sec &= ~(1 << 7); |
||||
sec |= (enable << 7); |
||||
writeRegister(kSecondReg, sec); |
||||
} |
||||
|
||||
uint8_t DS1302::seconds() { |
||||
return registerBcdToDec(kSecondReg, 6); |
||||
} |
||||
|
||||
uint8_t DS1302::minutes() { |
||||
return registerBcdToDec(kMinuteReg); |
||||
} |
||||
|
||||
uint8_t DS1302::hour() { |
||||
uint8_t hr = readRegister(kHourReg); |
||||
uint8_t adj; |
||||
if (hr & 128) // 12-hour mode
|
||||
adj = 12 * ((hr & 32) >> 5); |
||||
else // 24-hour mode
|
||||
adj = 10 * ((hr & (32 + 16)) >> 4); |
||||
hr = (hr & 15) + adj; |
||||
return hr; |
||||
} |
||||
|
||||
uint8_t DS1302::date() { |
||||
return registerBcdToDec(kDateReg, 5); |
||||
} |
||||
|
||||
uint8_t DS1302::month() { |
||||
return registerBcdToDec(kMonthReg, 4); |
||||
} |
||||
|
||||
Time::Day DS1302::day() { |
||||
return static_cast<Time::Day>(registerBcdToDec(kDayReg, 2)); |
||||
} |
||||
|
||||
uint16_t DS1302::year() { |
||||
return 2000 + registerBcdToDec(kYearReg); |
||||
} |
||||
|
||||
Time DS1302::time() { |
||||
return Time(year(), month(), date(), |
||||
hour(), minutes(), seconds(), |
||||
day()); |
||||
} |
||||
|
||||
void DS1302::seconds(const uint8_t sec) { |
||||
registerDecToBcd(kSecondReg, sec, 6); |
||||
} |
||||
|
||||
void DS1302::minutes(const uint8_t min) { |
||||
registerDecToBcd(kMinuteReg, min, 6); |
||||
} |
||||
|
||||
void DS1302::hour(const uint8_t hr) { |
||||
writeRegister(kHourReg, 0); // set 24-hour mode
|
||||
registerDecToBcd(kHourReg, hr, 5); |
||||
} |
||||
|
||||
void DS1302::date(const uint8_t date) { |
||||
registerDecToBcd(kDateReg, date, 5); |
||||
} |
||||
|
||||
void DS1302::month(const uint8_t mon) { |
||||
registerDecToBcd(kMonthReg, mon, 4); |
||||
} |
||||
|
||||
void DS1302::day(const Time::Day day) { |
||||
registerDecToBcd(kDayReg, static_cast<int>(day), 2); |
||||
} |
||||
|
||||
void DS1302::year(uint16_t yr) { |
||||
yr -= 2000; |
||||
registerDecToBcd(kYearReg, yr); |
||||
} |
||||
|
||||
void DS1302::time(const Time t) { |
||||
seconds(t.sec); |
||||
minutes(t.min); |
||||
hour(t.hr); |
||||
date(t.date); |
||||
month(t.mon); |
||||
day(t.day); |
||||
year(t.yr); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,329 @@ |
||||
/**
|
||||
* MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. |
||||
* Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) |
||||
* Created by Miguel Balboa (circuitito.com), Jan, 2012. |
||||
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) |
||||
* Released into the public domain. |
||||
*
|
||||
* Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. |
||||
* Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board.
|
||||
*
|
||||
* There are three hardware components involved: |
||||
* 1) The micro controller: An Arduino |
||||
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC |
||||
* 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. |
||||
*
|
||||
* The microcontroller and card reader uses SPI for communication. |
||||
* The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf
|
||||
*
|
||||
* The card reader and the tags communicate using a 13.56MHz electromagnetic field. |
||||
* The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision". |
||||
* A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
|
||||
* Details are found in chapter 6, Type A – Initialization and anticollision. |
||||
*
|
||||
* If only the PICC UID is wanted, the above documents has all the needed information. |
||||
* To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected. |
||||
* The MIFARE Classic chips and protocol is described in the datasheets: |
||||
* 1K: http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
|
||||
* 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.pdf
|
||||
* Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf
|
||||
* The MIFARE Ultralight chip and protocol is described in the datasheets: |
||||
* Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
|
||||
* Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf
|
||||
*
|
||||
* MIFARE Classic 1K (MF1S503x): |
||||
* Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. |
||||
* The blocks are numbered 0-63. |
||||
* Block 3 in each sector is the Sector Trailer. See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7:
|
||||
* Bytes 0-5: Key A |
||||
* Bytes 6-8: Access Bits |
||||
* Bytes 9: User data |
||||
* Bytes 10-15: Key B (or user data) |
||||
* Block 0 is read only manufacturer data. |
||||
* To access a block, an authentication using a key from the block's sector must be performed first. |
||||
* Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11). |
||||
* All keys are set to FFFFFFFFFFFFh at chip delivery. |
||||
* Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked. |
||||
* To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns. |
||||
* MIFARE Classic 4K (MF1S703x): |
||||
* Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. |
||||
* The blocks are numbered 0-255. |
||||
* The last block in each sector is the Sector Trailer like above. |
||||
* MIFARE Classic Mini (MF1 IC S20): |
||||
* Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. |
||||
* The blocks are numbered 0-19. |
||||
* The last block in each sector is the Sector Trailer like above. |
||||
*
|
||||
* MIFARE Ultralight (MF0ICU1): |
||||
* Has 16 pages of 4 bytes = 64 bytes. |
||||
* Pages 0 + 1 is used for the 7-byte UID. |
||||
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
|
||||
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. |
||||
* Pages 4-15 are read/write unless blocked by the lock bytes in page 2.
|
||||
* MIFARE Ultralight C (MF0ICU2): |
||||
* Has 48 pages of 4 bytes = 64 bytes. |
||||
* Pages 0 + 1 is used for the 7-byte UID. |
||||
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
|
||||
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. |
||||
* Pages 4-39 are read/write unless blocked by the lock bytes in page 2.
|
||||
* Page 40 Lock bytes |
||||
* Page 41 16 bit one way counter |
||||
* Pages 42-43 Authentication configuration |
||||
* Pages 44-47 Authentication key
|
||||
*/ |
||||
#ifndef MFRC522_h |
||||
#define MFRC522_h |
||||
|
||||
#include <Arduino.h> |
||||
#include "../SPI/SPI.h" |
||||
|
||||
class MFRC522 { |
||||
public: |
||||
// MFRC522 registers. Described in chapter 9 of the datasheet.
|
||||
// When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3)
|
||||
enum PCD_Register { |
||||
// Page 0: Command and status
|
||||
// 0x00 // reserved for future use
|
||||
CommandReg = 0x01 << 1, // starts and stops command execution
|
||||
ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits
|
||||
DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits
|
||||
ComIrqReg = 0x04 << 1, // interrupt request bits
|
||||
DivIrqReg = 0x05 << 1, // interrupt request bits
|
||||
ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed
|
||||
Status1Reg = 0x07 << 1, // communication status bits
|
||||
Status2Reg = 0x08 << 1, // receiver and transmitter status bits
|
||||
FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer
|
||||
FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer
|
||||
WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning
|
||||
ControlReg = 0x0C << 1, // miscellaneous control registers
|
||||
BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames
|
||||
CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface
|
||||
// 0x0F // reserved for future use
|
||||
|
||||
// Page 1:Command
|
||||
// 0x10 // reserved for future use
|
||||
ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving
|
||||
TxModeReg = 0x12 << 1, // defines transmission data rate and framing
|
||||
RxModeReg = 0x13 << 1, // defines reception data rate and framing
|
||||
TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2
|
||||
TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation
|
||||
TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver
|
||||
RxSelReg = 0x17 << 1, // selects internal receiver settings
|
||||
RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder
|
||||
DemodReg = 0x19 << 1, // defines demodulator settings
|
||||
// 0x1A // reserved for future use
|
||||
// 0x1B // reserved for future use
|
||||
MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters
|
||||
MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters
|
||||
// 0x1E // reserved for future use
|
||||
SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface
|
||||
|
||||
// Page 2: Configuration
|
||||
// 0x20 // reserved for future use
|
||||
CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation
|
||||
CRCResultRegL = 0x22 << 1, |
||||
// 0x23 // reserved for future use
|
||||
ModWidthReg = 0x24 << 1, // controls the ModWidth setting?
|
||||
// 0x25 // reserved for future use
|
||||
RFCfgReg = 0x26 << 1, // configures the receiver gain
|
||||
GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
|
||||
CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation
|
||||
ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation
|
||||
TModeReg = 0x2A << 1, // defines settings for the internal timer
|
||||
TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
|
||||
TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value
|
||||
TReloadRegL = 0x2D << 1, |
||||
TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value
|
||||
TCounterValueRegL = 0x2F << 1, |
||||
|
||||
// Page 3:Test Registers
|
||||
// 0x30 // reserved for future use
|
||||
TestSel1Reg = 0x31 << 1, // general test signal configuration
|
||||
TestSel2Reg = 0x32 << 1, // general test signal configuration
|
||||
TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7
|
||||
TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus
|
||||
TestBusReg = 0x35 << 1, // shows the status of the internal test bus
|
||||
AutoTestReg = 0x36 << 1, // controls the digital self test
|
||||
VersionReg = 0x37 << 1, // shows the software version
|
||||
AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2
|
||||
TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1
|
||||
TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2
|
||||
TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels
|
||||
// 0x3C // reserved for production tests
|
||||
// 0x3D // reserved for production tests
|
||||
// 0x3E // reserved for production tests
|
||||
// 0x3F // reserved for production tests
|
||||
}; |
||||
|
||||
// MFRC522 comands. Described in chapter 10 of the datasheet.
|
||||
enum PCD_Command { |
||||
PCD_Idle = 0x00, // no action, cancels current command execution
|
||||
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
|
||||
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
|
||||
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test
|
||||
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
|
||||
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
|
||||
PCD_Receive = 0x08, // activates the receiver circuits
|
||||
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
|
||||
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
|
||||
PCD_SoftReset = 0x0F // resets the MFRC522
|
||||
}; |
||||
|
||||
// Commands sent to the PICC.
|
||||
enum PICC_Command { |
||||
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
|
||||
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
|
||||
PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
|
||||
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision.
|
||||
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
|
||||
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 1
|
||||
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1
|
||||
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
|
||||
// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
|
||||
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
|
||||
// The read/write commands can also be used for MIFARE Ultralight.
|
||||
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
|
||||
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
|
||||
PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
|
||||
PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
|
||||
PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
|
||||
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
|
||||
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
|
||||
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
|
||||
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
|
||||
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
|
||||
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
|
||||
}; |
||||
|
||||
// MIFARE constants that does not fit anywhere else
|
||||
enum MIFARE_Misc { |
||||
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
|
||||
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
|
||||
}; |
||||
|
||||
// PICC types we can detect. Remember to update PICC_GetTypeName() if you add more.
|
||||
enum PICC_Type { |
||||
PICC_TYPE_UNKNOWN = 0, |
||||
PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4
|
||||
PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC)
|
||||
PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes
|
||||
PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB
|
||||
PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB
|
||||
PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C
|
||||
PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus
|
||||
PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
|
||||
PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete.
|
||||
}; |
||||
|
||||
// Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more.
|
||||
enum StatusCode { |
||||
STATUS_OK = 1, // Success
|
||||
STATUS_ERROR = 2, // Error in communication
|
||||
STATUS_COLLISION = 3, // Collission detected
|
||||
STATUS_TIMEOUT = 4, // Timeout in communication.
|
||||
STATUS_NO_ROOM = 5, // A buffer is not big enough.
|
||||
STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-)
|
||||
STATUS_INVALID = 7, // Invalid argument.
|
||||
STATUS_CRC_WRONG = 8, // The CRC_A does not match
|
||||
STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK.
|
||||
}; |
||||
|
||||
// A struct used for passing the UID of a PICC.
|
||||
typedef struct { |
||||
byte size; // Number of bytes in the UID. 4, 7 or 10.
|
||||
byte uidByte[10]; |
||||
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
|
||||
} Uid; |
||||
|
||||
// A struct used for passing a MIFARE Crypto1 key
|
||||
typedef struct { |
||||
byte keyByte[MF_KEY_SIZE]; |
||||
} MIFARE_Key; |
||||
|
||||
// Member variables
|
||||
Uid uid; // Used by PICC_ReadCardSerial().
|
||||
|
||||
// Size of the MFRC522 FIFO
|
||||
static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions for setting up the Arduino
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
MFRC522(byte chipSelectPin, byte resetPowerDownPin); |
||||
void setSPIConfig(); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic interface functions for communicating with the MFRC522
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
void PCD_WriteRegister(byte reg, byte value); |
||||
void PCD_WriteRegister(byte reg, byte count, byte *values); |
||||
byte PCD_ReadRegister(byte reg); |
||||
void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0); |
||||
void setBitMask(unsigned char reg, unsigned char mask); |
||||
void PCD_SetRegisterBitMask(byte reg, byte mask); |
||||
void PCD_ClearRegisterBitMask(byte reg, byte mask); |
||||
byte PCD_CalculateCRC(byte *data, byte length, byte *result); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions for manipulating the MFRC522
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
void PCD_Init(); |
||||
void PCD_Reset(); |
||||
void PCD_AntennaOn(); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions for communicating with PICCs
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
byte PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); |
||||
byte PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); |
||||
|
||||
byte PICC_RequestA(byte *bufferATQA, byte *bufferSize); |
||||
byte PICC_WakeupA(byte *bufferATQA, byte *bufferSize); |
||||
byte PICC_REQA_or_WUPA( byte command, byte *bufferATQA, byte *bufferSize);
|
||||
byte PICC_Select(Uid *uid, byte validBits = 0); |
||||
byte PICC_HaltA(); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions for communicating with MIFARE PICCs
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); |
||||
void PCD_StopCrypto1(); |
||||
byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize); |
||||
byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize); |
||||
byte MIFARE_Decrement(byte blockAddr, long delta); |
||||
byte MIFARE_Increment(byte blockAddr, long delta); |
||||
byte MIFARE_Restore(byte blockAddr); |
||||
byte MIFARE_Transfer(byte blockAddr); |
||||
byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Support functions
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
byte PCD_MIFARE_Transceive( byte *sendData, byte sendLen, bool acceptTimeout = false); |
||||
const char *GetStatusCodeName(byte code); |
||||
byte PICC_GetType(byte sak); |
||||
const char *PICC_GetTypeName(byte type); |
||||
void PICC_DumpToSerial(Uid *uid); |
||||
void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key); |
||||
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); |
||||
void PICC_DumpMifareUltralightToSerial(); |
||||
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// Convenience functions - does not add extra functionality
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
bool PICC_IsNewCardPresent(); |
||||
bool PICC_ReadCardSerial();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// User functions
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// void MFRC522::UID_to_lcd(Uid *uid);
|
||||
|
||||
private: |
||||
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low)
|
||||
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
|
||||
byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data); |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,334 @@ |
||||
#include <stdint.h> |
||||
#include "PCD8544.h" |
||||
|
||||
#include <pins_arduino.h> |
||||
#include <avr/pgmspace.h> |
||||
|
||||
|
||||
|
||||
// LCD commands, Table 1, page 14
|
||||
#define PCD8544_FUNCTION_SET (1<<5) |
||||
#define PCD8544_FUNCTION_PD (1<<2) |
||||
#define PCD8544_FUNCTION_V (1<<1) |
||||
#define PCD8544_FUNCTION_H (1<<0) |
||||
|
||||
// Normal instructions, H = 0
|
||||
#define PCD8544_DISPLAY_CONTROL (1<<3) |
||||
#define PCD8544_DISPLAY_CONTROL_D (1<<2) |
||||
#define PCD8544_DISPLAY_CONTROL_E (1<<0) |
||||
#define PCD8544_DISPLAY_CONTROL_BLANK 0 |
||||
#define PCD8544_DISPLAY_CONTROL_NORMAL_MODE PCD8544_DISPLAY_CONTROL_D |
||||
#define PCD8544_DISPLAY_CONTROL_ALL_ON PCD8544_DISPLAY_CONTROL_E |
||||
#define PCD8544_DISPLAY_CONTROL_INVERSE (PCD8544_DISPLAY_CONTROL_D|PCD8544_DISPLAY_CONTROL_E) |
||||
|
||||
#define PCD8544_SET_Y_ADDRESS (1<<6) |
||||
#define PCD8544_Y_ADRESS_MASK 0b111 |
||||
#define PCD8544_SET_X_ADDRESS (1<<7) |
||||
#define PCD8544_X_ADRESS_MASK 0b01111111 |
||||
|
||||
// Extended instructions. H = 1
|
||||
#define PCD8544_TEMP_CONTROL (1<<2) |
||||
#define PCD8544_TEMP_TC1 (1<<1) |
||||
#define PCD8544_TEMP_TC0 (1<<0) |
||||
|
||||
#define PCD8544_BIAS (1<<4) |
||||
#define PCD8544_BIAS_BS2 (1<<2) |
||||
#define PCD8544_BIAS_BS1 (1<<1) |
||||
#define PCD8544_BIAS_BS0 (1<<0) |
||||
|
||||
#define PCD8544_VOP (1<<7) |
||||
|
||||
|
||||
const unsigned char PROGMEM small_num[][4] = { |
||||
{0x0e,0x15,0x0e,0x00}, // 48, zero
|
||||
{0x12,0x1f,0x10,0x00}, // 49, one
|
||||
{0x12,0x19,0x16,0x00}, // 50, two
|
||||
{0x11,0x15,0x0b,0x00}, // 51, three
|
||||
{0x07,0x04,0x1f,0x00}, // 52, four
|
||||
{0x17,0x15,0x09,0x00}, // 53, five
|
||||
{0x0e,0x15,0x09,0x00}, // 54, six
|
||||
{0x19,0x05,0x03,0x00}, // 55, seven
|
||||
{0x1a,0x15,0x0b,0x00}, // 56, eight
|
||||
{0x12,0x15,0x0e,0x00}, // 57, nine
|
||||
{0x00,0x10,0x00,0x00}, // 46, period
|
||||
}; |
||||
|
||||
|
||||
const unsigned char PROGMEM font6x8 [][5] = { |
||||
{0x00,0x00,0x00,0x00,0x00,}, // ' ' 32
|
||||
{0x00,0x00,0x5F,0x00,0x00,}, // '!' 33
|
||||
{0x00,0x07,0x00,0x07,0x00,}, // '"' 34
|
||||
{0x14,0x7F,0x14,0x7F,0x14,}, // '#' 35
|
||||
{0x24,0x2A,0x7F,0x2A,0x12,}, // '$' 36
|
||||
{0x23,0x13,0x08,0x64,0x62,}, // '%' 37
|
||||
{0x36,0x49,0x55,0x22,0x50,}, // '&' 38
|
||||
{0x00,0x05,0x03,0x00,0x00,}, // ''' 39
|
||||
{0x00,0x1C,0x22,0x41,0x00,}, // '(' 40
|
||||
{0x00,0x41,0x22,0x1C,0x00,}, // ')' 41
|
||||
{0x14,0x08,0x3E,0x08,0x14,}, // '*' 42
|
||||
{0x08,0x08,0x3E,0x08,0x08,}, // '+' 43
|
||||
{0x00,0x50,0x30,0x00,0x00,}, // ',' 44
|
||||
{0x08,0x08,0x08,0x08,0x08,}, // '-' 45
|
||||
{0x00,0x60,0x60,0x00,0x00,}, // '.' 46
|
||||
{0x20,0x10,0x08,0x04,0x02,}, // '/' 47
|
||||
{0x3E,0x51,0x49,0x45,0x3E,}, // '0' 48
|
||||
{0x00,0x42,0x7F,0x40,0x00,}, // '1' 49
|
||||
{0x42,0x61,0x51,0x49,0x46,}, // '2' 50
|
||||
{0x21,0x41,0x45,0x4B,0x31,}, // '3' 51
|
||||
{0x18,0x14,0x12,0x7F,0x10,}, // '4' 52
|
||||
{0x27,0x45,0x45,0x45,0x39,}, // '5' 53
|
||||
{0x3C,0x4A,0x49,0x49,0x30,}, // '6' 54
|
||||
{0x03,0x01,0x71,0x09,0x07,}, // '7' 55
|
||||
{0x36,0x49,0x49,0x49,0x36,}, // '8' 56
|
||||
{0x06,0x49,0x49,0x29,0x16,}, // '9' 57
|
||||
{0x00,0x36,0x36,0x00,0x00,}, // ':' 58
|
||||
{0x00,0x56,0x36,0x00,0x00,}, // ';' 59
|
||||
{0x08,0x14,0x22,0x41,0x00,}, // '<' 60
|
||||
{0x14,0x14,0x14,0x14,0x14,}, // '=' 61
|
||||
{0x00,0x41,0x22,0x14,0x08,}, // '>' 62
|
||||
{0x02,0x01,0x51,0x09,0x06,}, // '?' 63
|
||||
{0x32,0x49,0x79,0x41,0x3E,}, // '@' 64
|
||||
{0x7E,0x11,0x11,0x11,0x7E,}, // 'A' 65
|
||||
{0x7F,0x49,0x49,0x49,0x36,}, // 'B' 66
|
||||
{0x3E,0x41,0x41,0x41,0x22,}, // 'C' 67
|
||||
{0x7F,0x41,0x41,0x22,0x1C,}, // 'D' 68
|
||||
{0x7F,0x49,0x49,0x49,0x41,}, // 'E' 69
|
||||
{0x7F,0x09,0x09,0x01,0x01,}, // 'F' 70
|
||||
{0x3E,0x41,0x49,0x49,0x3A,}, // 'G' 71
|
||||
{0x7F,0x08,0x08,0x08,0x7F,}, // 'H' 72
|
||||
{0x00,0x41,0x7F,0x41,0x00,}, // 'I' 73
|
||||
{0x20,0x41,0x41,0x3F,0x01,}, // 'J' 74
|
||||
{0x7F,0x08,0x14,0x22,0x41,}, // 'K' 75
|
||||
{0x7F,0x40,0x40,0x40,0x40,}, // 'L' 76
|
||||
{0x7F,0x02,0x0C,0x02,0x7F,}, // 'M' 77
|
||||
{0x7F,0x04,0x08,0x10,0x7F,}, // 'N' 78
|
||||
{0x3E,0x41,0x41,0x41,0x3E,}, // 'O' 79
|
||||
{0x7F,0x09,0x09,0x09,0x06,}, // 'P' 80
|
||||
{0x3E,0x41,0x51,0x21,0x5E,}, // 'Q' 81
|
||||
{0x7F,0x09,0x19,0x29,0x46,}, // 'R' 82
|
||||
{0x26,0x49,0x49,0x49,0x32,}, // 'S' 83
|
||||
{0x01,0x01,0x7F,0x01,0x01,}, // 'T' 84
|
||||
{0x3F,0x40,0x40,0x40,0x3F,}, // 'U' 85
|
||||
{0x1F,0x20,0x40,0x20,0x1F,}, // 'V' 86
|
||||
{0x3F,0x40,0x38,0x40,0x3F,}, // 'W' 87
|
||||
{0x63,0x14,0x08,0x14,0x63,}, // 'X' 88
|
||||
{0x07,0x08,0x70,0x08,0x07,}, // 'Y' 89
|
||||
{0x61,0x51,0x49,0x45,0x43,}, // 'Z' 90
|
||||
{0x00,0x7F,0x41,0x41,0x00,}, // '[' 91
|
||||
{0x02,0x04,0x08,0x10,0x20,}, // '\' 92
|
||||
{0x00,0x41,0x41,0x7F,0x00,}, // ']' 93
|
||||
{0x04,0x02,0x01,0x02,0x04,}, // '^' 94
|
||||
{0x40,0x40,0x40,0x40,0x40,}, // '_' 95
|
||||
{0x00,0x01,0x02,0x04,0x00,}, // '`' 96
|
||||
{0x20,0x54,0x54,0x54,0x78,}, // 'a' 97
|
||||
{0x7F,0x48,0x44,0x44,0x38,}, // 'b' 98
|
||||
{0x38,0x44,0x44,0x44,0x20,}, // 'c' 99
|
||||
{0x38,0x44,0x44,0x48,0x3F,}, // 'd' 100
|
||||
{0x38,0x54,0x54,0x54,0x18,}, // 'e' 101
|
||||
{0x08,0x7E,0x09,0x01,0x02,}, // 'f' 102
|
||||
{0x0C,0x52,0x52,0x52,0x3E,}, // 'g' 103
|
||||
{0x7F,0x08,0x04,0x04,0x78,}, // 'h' 104
|
||||
{0x00,0x44,0x7D,0x40,0x00,}, // 'i' 105
|
||||
{0x20,0x40,0x45,0x3C,0x00,}, // 'j' 106
|
||||
{0x7F,0x10,0x28,0x44,0x00,}, // 'k' 107
|
||||
{0x00,0x41,0x7F,0x40,0x00,}, // 'l' 108
|
||||
{0x7C,0x04,0x18,0x04,0x78,}, // 'm' 109
|
||||
{0x7C,0x08,0x04,0x04,0x78,}, // 'n' 110
|
||||
{0x38,0x44,0x44,0x44,0x38,}, // 'o' 111
|
||||
{0x7C,0x14,0x14,0x14,0x08,}, // 'p' 112
|
||||
{0x08,0x14,0x14,0x18,0x7C,}, // 'q' 113
|
||||
{0x7C,0x08,0x04,0x04,0x08,}, // 'r' 114
|
||||
{0x48,0x54,0x54,0x54,0x20,}, // 's' 115
|
||||
{0x04,0x3F,0x44,0x40,0x20,}, // 't' 116
|
||||
{0x3C,0x40,0x40,0x20,0x7C,}, // 'u' 117
|
||||
{0x1C,0x20,0x40,0x20,0x1C,}, // 'v' 118
|
||||
{0x3C,0x40,0x30,0x40,0x3C,}, // 'w' 119
|
||||
{0x44,0x28,0x10,0x28,0x44,}, // 'x' 120
|
||||
{0x0C,0x50,0x50,0x50,0x3C,}, // 'y' 121
|
||||
{0x44,0x64,0x54,0x4C,0x44,}, // 'z' 122
|
||||
{0x00,0x08,0x36,0x41,0x00,}, // '{' 123
|
||||
{0x00,0x00,0x7F,0x00,0x00,}, // '|' 124
|
||||
{0x00,0x41,0x36,0x08,0x00,}, // '}' 125
|
||||
{0x10,0x08,0x08,0x10,0x08,}, // '~' 126
|
||||
{0x08,0x1C,0x2A,0x08,0x08,} // <- 127
|
||||
}; |
||||
|
||||
|
||||
|
||||
|
||||
PCD8544::PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t hardware_spi) |
||||
{ |
||||
dc = dc_pin; |
||||
cs = cs_pin; |
||||
reset = reset_pin; |
||||
hardware_spi_num = hardware_spi; |
||||
if (hardware_spi_num > 2) |
||||
hardware_spi_num = 2; |
||||
#ifndef MAPLE |
||||
sdin = MOSI; |
||||
sclk = SCK; |
||||
#else |
||||
sdin = 11; // Change to maple names
|
||||
sclk = 13; |
||||
if (hardware_spi_num == 2) { |
||||
sdin = 32; |
||||
sclk = 34; |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
PCD8544::PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t sdin_pin, uint8_t sclk_pin) |
||||
{ |
||||
dc = dc_pin; |
||||
cs = cs_pin; |
||||
reset = reset_pin; |
||||
sdin = sdin_pin; |
||||
sclk = sclk_pin; |
||||
hardware_spi_num = 0; |
||||
} |
||||
|
||||
void PCD8544::begin(void) |
||||
{ |
||||
pinMode(cs, OUTPUT); |
||||
pinMode(reset, OUTPUT); |
||||
pinMode(dc, OUTPUT); |
||||
pinMode(sdin, OUTPUT); |
||||
pinMode(sclk, OUTPUT); |
||||
|
||||
|
||||
|
||||
if (hardware_spi_num > 0) { |
||||
pinMode(SS, OUTPUT); // To ensure master mode
|
||||
SPCR |= (1<<SPE) | (1<<MSTR); |
||||
} |
||||
digitalWrite(reset, LOW); |
||||
delay(1); |
||||
digitalWrite(reset, HIGH); |
||||
|
||||
// Extenden instructions and !powerdown
|
||||
// and horizontal adressing (autoincrement of x-adress)
|
||||
command(PCD8544_FUNCTION_SET | PCD8544_FUNCTION_H); |
||||
// Set Vop to 0x3F
|
||||
command(PCD8544_VOP | 0xBF); |
||||
// Vlcd temp. coeff. 0
|
||||
command(PCD8544_TEMP_CONTROL); |
||||
// Bias system 4, 1:48
|
||||
command(PCD8544_BIAS | PCD8544_BIAS_BS1 | PCD8544_BIAS_BS0); |
||||
// Set H = 0 for normal instructions
|
||||
command(PCD8544_FUNCTION_SET); |
||||
// Normal mode
|
||||
command(PCD8544_DISPLAY_CONTROL | PCD8544_DISPLAY_CONTROL_NORMAL_MODE); |
||||
} |
||||
|
||||
|
||||
void PCD8544::clear(void) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < PCD8544_WIDTH*PCD8544_LINES; i++) |
||||
data(0); |
||||
} |
||||
|
||||
WRITE_RESULT PCD8544::write(uint8_t ch) |
||||
{ |
||||
uint8_t i; |
||||
|
||||
if (ch == '\r') |
||||
gotoRc(current_row, 0); |
||||
if (ch == '\n') |
||||
gotoRc(current_row+1, current_column); |
||||
if (ch >= ' ' && ch <= 127) { |
||||
for (i = 0; i < 5; i++) |
||||
data(pgm_read_byte(&font6x8[ch-' '][i]) <<1); |
||||
data(0); |
||||
} |
||||
|
||||
WRITE_RETURN; |
||||
} |
||||
|
||||
//void PCD8544::toggle_invert(void) {
|
||||
// invert_line = !invert_line;
|
||||
//}
|
||||
|
||||
void PCD8544::data(uint8_t data) { |
||||
// if (invert_line)
|
||||
// send(1, ~data);
|
||||
// else
|
||||
send(1, data); |
||||
} |
||||
|
||||
void PCD8544::command(uint8_t data) |
||||
{ |
||||
send(0, data); |
||||
} |
||||
|
||||
void PCD8544::send(uint8_t data_or_command, uint8_t data) |
||||
{ |
||||
digitalWrite(dc, data_or_command); |
||||
digitalWrite(cs, LOW); |
||||
if (hardware_spi_num == 0) { |
||||
shiftOut(sdin, sclk, MSBFIRST, data); |
||||
} else { |
||||
SPDR = data; |
||||
while(!(SPSR & (1<<SPIF))) ; |
||||
} |
||||
digitalWrite(cs, HIGH); |
||||
if(data_or_command) |
||||
inc_row_column(); |
||||
} |
||||
|
||||
|
||||
void PCD8544::setCursor(uint8_t column, uint8_t row) |
||||
{ |
||||
gotoRc(row, 6*column); |
||||
} |
||||
|
||||
|
||||
void PCD8544::gotoRc(uint8_t row, uint8_t column) |
||||
{ |
||||
if (row >= PCD8544_LINES) |
||||
row %= PCD8544_LINES; |
||||
if (column >= PCD8544_WIDTH) |
||||
row %= PCD8544_WIDTH; |
||||
command(PCD8544_SET_X_ADDRESS | column); |
||||
command(PCD8544_SET_Y_ADDRESS | row); |
||||
current_row = row; |
||||
current_column = column; |
||||
} |
||||
|
||||
void PCD8544::inc_row_column(void) |
||||
{ |
||||
if (++current_column >= PCD8544_WIDTH) { |
||||
current_column = 0; |
||||
if (++current_row >= PCD8544_LINES) |
||||
current_row = 0; |
||||
} |
||||
// invert_line = false;
|
||||
} |
||||
|
||||
|
||||
void PCD8544::smallNum(uint8_t num, uint8_t shift) |
||||
{ |
||||
uint8_t i; |
||||
for (i = 0; i < 4; i++) |
||||
data(pgm_read_byte(&small_num[num][i])<<shift); |
||||
} |
||||
|
||||
|
||||
void PCD8544::clearRestOfLine(void) |
||||
{ |
||||
while (current_column != 0) |
||||
data(0); |
||||
} |
||||
|
||||
void PCD8544::bitmap(const byte bdata[], uint8_t rows, uint8_t columns) |
||||
{ |
||||
uint8_t row, column, i; |
||||
uint8_t toprow = current_row; |
||||
uint8_t startcolumn = current_column; |
||||
for (row = 0, i = 0; row < rows; row++) { |
||||
gotoRc(row+toprow, startcolumn); |
||||
for (column = 0; column < columns; column++) { |
||||
data(pgm_read_byte(&bdata[i++])); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
#ifndef PCD8544_H |
||||
#define PCD8544_H |
||||
|
||||
#include <stdint.h> |
||||
#include <Print.h> |
||||
|
||||
|
||||
#include <Arduino.h> // Arduino 1.0 |
||||
#define WRITE_RESULT size_t |
||||
#define WRITE_RETURN return 1; |
||||
|
||||
|
||||
|
||||
//#ifndef __AVR-GCC__
|
||||
//#define MAPLE 1
|
||||
//
|
||||
//#ifndef SPI_NUM
|
||||
//#define SPI_NUM 1
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
class PCD8544 : public Print { |
||||
public: |
||||
// Constructor for harware SPI
|
||||
PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t hardware_spi = 1); |
||||
|
||||
// Constructor for software SPI.
|
||||
PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t sdin_pin, uint8_t sclk_pin); |
||||
|
||||
// Call this first
|
||||
void begin(void); |
||||
|
||||
// Clear lcd without changing location
|
||||
void clear(void); |
||||
|
||||
// Change current position to (character) column and row
|
||||
void setCursor(uint8_t column, uint8_t row); |
||||
|
||||
// Change current location to 0 <= row <= 5,
|
||||
// 0 <= pixel_column <= 83
|
||||
void gotoRc(uint8_t row, uint8_t pixel_column); |
||||
|
||||
// Send data to lcd. Will draw data as one pixel wide, 8 pixel high.
|
||||
// LSB up.
|
||||
void data(uint8_t data); |
||||
|
||||
// Small numbers. 0<= num <=9 for number and num = 10 for decimal
|
||||
// point. Optional parameter shift will move the numbers up/down.
|
||||
// shift shold be 0,1,2,3 for the digit to be visible.
|
||||
void smallNum(uint8_t num, uint8_t shift = 1); |
||||
|
||||
void clearRestOfLine(void); |
||||
void bitmap(const byte *data, uint8_t rows, uint8_t columns); |
||||
|
||||
// void toggle_invert(void);
|
||||
|
||||
private: |
||||
void send(uint8_t dc, uint8_t data); |
||||
void command(uint8_t data); |
||||
virtual WRITE_RESULT write(uint8_t ch); |
||||
void inc_row_column(void); |
||||
uint8_t dc; |
||||
uint8_t cs; |
||||
uint8_t reset; |
||||
uint8_t hardware_spi_num; |
||||
uint8_t sdin; |
||||
uint8_t sclk; |
||||
uint8_t current_row, current_column; |
||||
uint8_t invert_line; |
||||
}; |
||||
|
||||
#define PCD8544_LINES 6 |
||||
#define PCD8544_COLS 14 |
||||
#define PCD8544_WIDTH 84 |
||||
#define PCD8544_HEIGHT 48 |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,24 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../DS1302/DS1302.cpp
|
||||
|
||||
OBJS += \
|
||||
./DS1302/DS1302.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./DS1302/DS1302.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
DS1302/%.o: ../DS1302/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,24 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../MFRC522/MFRC522.cpp
|
||||
|
||||
OBJS += \
|
||||
./MFRC522/MFRC522.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./MFRC522/MFRC522.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
MFRC522/%.o: ../MFRC522/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,24 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../PCD8544/PCD8544.cpp
|
||||
|
||||
OBJS += \
|
||||
./PCD8544/PCD8544.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./PCD8544/PCD8544.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
PCD8544/%.o: ../PCD8544/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,27 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../SD/File.cpp \ |
||||
../SD/SD.cpp
|
||||
|
||||
OBJS += \
|
||||
./SD/File.o \ |
||||
./SD/SD.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./SD/File.d \ |
||||
./SD/SD.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
SD/%.o: ../SD/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/usr/share/arduino/hardware/arduino/cores/arduino" -I"/home/delmadord/dev/arduino/Bakalarka/SD/utility" -I"/usr/share/arduino/hardware/arduino/variants/standard" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO=1:105+dfsg2-1 -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,30 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../SD/utility/Sd2Card.cpp \ |
||||
../SD/utility/SdFile.cpp \ |
||||
../SD/utility/SdVolume.cpp
|
||||
|
||||
OBJS += \
|
||||
./SD/utility/Sd2Card.o \ |
||||
./SD/utility/SdFile.o \ |
||||
./SD/utility/SdVolume.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./SD/utility/Sd2Card.d \ |
||||
./SD/utility/SdFile.d \ |
||||
./SD/utility/SdVolume.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
SD/utility/%.o: ../SD/utility/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/usr/share/arduino/hardware/arduino/cores/arduino" -I"/home/delmadord/dev/arduino/Bakalarka/SD/utility" -I"/usr/share/arduino/hardware/arduino/variants/standard" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO=1:105+dfsg2-1 -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,27 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../SDFAT16/Fat16.cpp \ |
||||
../SDFAT16/SdCard.cpp
|
||||
|
||||
OBJS += \
|
||||
./SDFAT16/Fat16.o \ |
||||
./SDFAT16/SdCard.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./SDFAT16/Fat16.d \ |
||||
./SDFAT16/SdCard.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
SDFAT16/%.o: ../SDFAT16/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,24 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../SPI/SPI.cpp
|
||||
|
||||
OBJS += \
|
||||
./SPI/SPI.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./SPI/SPI.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
SPI/%.o: ../SPI/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,24 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../SerialCommand/SerialCommand.cpp
|
||||
|
||||
OBJS += \
|
||||
./SerialCommand/SerialCommand.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./SerialCommand/SerialCommand.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
SerialCommand/%.o: ../SerialCommand/%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,27 @@ |
||||
################################################################################
|
||||
# Automatically-generated file. Do not edit!
|
||||
################################################################################
|
||||
|
||||
# Add inputs and outputs from these tool invocations to the build variables
|
||||
CPP_SRCS += \
|
||||
../Bakalarka.cpp \ |
||||
../rotary.cpp
|
||||
|
||||
OBJS += \
|
||||
./Bakalarka.o \ |
||||
./rotary.o
|
||||
|
||||
CPP_DEPS += \
|
||||
./Bakalarka.d \ |
||||
./rotary.d
|
||||
|
||||
|
||||
# Each subdirectory must supply rules for building sources it contributes
|
||||
%.o: ../%.cpp |
||||
@echo 'Building file: $<'
|
||||
@echo 'Invoking: AVR C++ Compiler'
|
||||
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
|
||||
@echo 'Finished building: $<'
|
||||
@echo ' '
|
||||
|
||||
|
@ -0,0 +1,38 @@ |
||||
/* Arduino FAT16 Library
|
||||
* Copyright (C) 2008 by William Greiman |
||||
* |
||||
* This file is part of the Arduino FAT16 Library |
||||
* |
||||
* This Library is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
/**
|
||||
* \file |
||||
* Configuration file |
||||
*/ |
||||
#ifndef Fat16Config_h |
||||
#define Fat16Config_h |
||||
/**
|
||||
* Allow use of deprecated functions if non-zero |
||||
*/ |
||||
#define ALLOW_DEPRECATED_FUNCTIONS 1 |
||||
/**
|
||||
* SdCard::writeBlock will protect block zero if set non-zero |
||||
*/ |
||||
#define SD_PROTECT_BLOCK_ZERO 1 |
||||
/**
|
||||
* Set non-zero to allow access to Fat16 internals by cardInfo debug sketch |
||||
*/ |
||||
#define FAT16_DEBUG_SUPPORT 1 |
||||
#endif // Fat16Config_h
|
@ -0,0 +1,208 @@ |
||||
/* Arduino FAT16 Library
|
||||
* Copyright (C) 2008 by William Greiman |
||||
*
|
||||
* This file is part of the Arduino FAT16 Library |
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
*
|
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/**
|
||||
\mainpage Arduino Fat16 Library |
||||
<CENTER>Copyright © 2008 by William Greiman |
||||
</CENTER> |
||||
|
||||
\section Intro Introduction |
||||
The Arduino Fat16 Library is a minimal implementation of the FAT16 file system |
||||
on standard SD flash memory cards. Fat16 supports read, write, file |
||||
creation, deletion, and truncation.
|
||||
|
||||
The Fat16 class only supports access to files in the root directory and only |
||||
supports short 8.3 names. Directory time and date fields for creation |
||||
and modification can be maintained by providing a date/time callback |
||||
function \link Fat16::dateTimeCallback() dateTimeCallback()\endlink |
||||
or calling \link Fat16::timestamp() timestamp()\endlink. |
||||
|
||||
Fat16 was designed to use the Arduino Print class which |
||||
allows files to be written with \link Print::print() print() \endlink and
|
||||
\link Print::println() println()\endlink. |
||||
|
||||
\section comment Bugs and Comments |
||||
|
||||
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net. |
||||
|
||||
|
||||
\section SDcard SD Cards |
||||
|
||||
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and |
||||
most consumer devices use the 4-bit parallel SD protocol. A card that |
||||
functions well on A PC or Mac may not work well on the Arduino. |
||||
|
||||
Most cards have good SPI read performance but cards vary widely in SPI |
||||
write performance. Write performance is limited by how efficiently the |
||||
card manages internal erase/remapping operations. The Arduino cannot |
||||
optimize writes to reduce erase operations because of its limit RAM. |
||||
|
||||
SanDisk cards generally have good write performance. They seem to have |
||||
more internal RAM buffering than other cards and therefore can limit |
||||
the number of flash erase operations that the Arduino forces due to its |
||||
limited RAM. |
||||
|
||||
Some Dane-Elec cards have a write speed that is only 20% as fast as |
||||
a good SanDisk card. |
||||
|
||||
|
||||
\section Hardware Hardware Configuration |
||||
Fat16 was developed using an <A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
|
||||
<A HREF = "http://ladyada.net/make/gpsshield/modules.html"> GPS Shield</A>. |
||||
|
||||
The hardware interface to the SD card should not use a resistor based level |
||||
shifter. SdCard::init() sets the SPI bus frequency to 8 MHz which results in |
||||
signal rise times that are too slow for the edge detectors in many newer SD card |
||||
controllers when resistor voltage dividers are used. |
||||
|
||||
The 5 to 3.3 V level shifter for 5 V arduinos should be IC based like the |
||||
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield |
||||
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the |
||||
74LCX245. |
||||
|
||||
If you are using a resistor based level shifter and are having problems try |
||||
setting the SPI bus frequency to 4 MHz. This can be done by using |
||||
card.init(true) to initialize the SD card. |
||||
|
||||
|
||||
\section Fat16Class Fat16 Usage |
||||
|
||||
The class Fat16 is a minimal implementation of FAT16 on standard SD cards. |
||||
High Capacity SD cards, SDHC, are not supported. It should work on all |
||||
standard cards from 8MB to 2GB formatted with a FAT16 file system. |
||||
|
||||
\note
|
||||
The Arduino Print class uses character |
||||
at a time writes so it was necessary to use a \link Fat16::sync() sync() \endlink |
||||
function to control when data is written to the SD card. |
||||
|
||||
\par |
||||
An application which writes to a file using \link Print::print() print()\endlink,
|
||||
\link Print::println() println() \endlink
|
||||
or \link Fat16::write write() \endlink must call \link Fat16::sync() sync() \endlink
|
||||
at the appropriate time to force data and directory information to be written
|
||||
to the SD Card. Data and directory information are also written to the SD card |
||||
when \link Fat16::close() close() \endlink is called. |
||||
|
||||
\par
|
||||
Applications must use care calling \link Fat16::sync() sync() \endlink |
||||
since 2048 bytes of I/O is required to update file and |
||||
directory information. This includes writing the current data block, reading |
||||
the block that contains the directory entry for update, writing the directory |
||||
block back and reading back the current data block. |
||||
|
||||
Fat16 only supports access to files in the root directory and only supports |
||||
short 8.3 names. |
||||
|
||||
It is possible to open a file with two or more instances of Fat16. A file may |
||||
be corrupted if data is written to the file by more than one instance of Fat16. |
||||
|
||||
Short names are limited to 8 characters followed by an optional period (.) |
||||
and extension of up to 3 characters. The characters may be any combination |
||||
of letters and digits. The following special characters are also allowed: |
||||
|
||||
$ % ' - _ @ ~ ` ! ( ) { } ^ # & |
||||
|
||||
Short names are always converted to upper case and their original case |
||||
value is lost.
|
||||
|
||||
Fat16 uses a slightly restricted form of short names. |
||||
Only printable ASCII characters are supported. No characters with code point |
||||
values greater than 127 are allowed. Space is not allowed even though space
|
||||
was allowed in the API of early versions of DOS. |
||||
|
||||
Fat16 has been optimized for The Arduino ATmega168. Minimizing RAM use is the |
||||
highest priority goal followed by flash use and finally performance.
|
||||
Most SD cards only support 512 byte block write operations so a 512 byte |
||||
cache buffer is used by Fat16. This is the main use of RAM. A small |
||||
amount of RAM is used to store key volume and file information. |
||||
Flash memory usage can be controlled by selecting options in Fat16Config.h. |
||||
|
||||
\section HowTo How to format SD Cards as FAT16 Volumes |
||||
|
||||
Microsoft operating systems support removable media formatted with a
|
||||
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector |
||||
in block zero. |
||||
|
||||
Microsoft operating systems expect MBR formatted removable media
|
||||
to have only one partition. The first partition should be used. |
||||
|
||||
Microsoft operating systems do not support partitioning SD flash cards. |
||||
If you erase an SD card with a program like KillDisk, Most versions of |
||||
Windows will format the card as a super floppy. |
||||
|
||||
The best way to restore an SD card's MBR is to use SDFormatter
|
||||
which can be downloaded from: |
||||
|
||||
http://www.sdcard.org/consumers/formatter/
|
||||
|
||||
SDFormatter does not have an option for FAT type so it may format |
||||
small cards as FAT12. |
||||
|
||||
After the MBR is restored by SDFormatter you may need to reformat small |
||||
cards that have been formatted FAT12 to force the volume type to be FAT16.
|
||||
|
||||
The FAT type, FAT12, FAT16, or FAT32, is determined by the count
|
||||
of clusters on the volume and nothing else. |
||||
|
||||
Microsoft published the following code for determining FAT type: |
||||
|
||||
\code |
||||
if (CountOfClusters < 4085) { |
||||
// Volume is FAT12
|
||||
} |
||||
else if (CountOfClusters < 65525) { |
||||
// Volume is FAT16
|
||||
} |
||||
else { |
||||
// Volume is FAT32
|
||||
} |
||||
|
||||
\endcode |
||||
If you format a FAT volume with an OS utility , choose a cluster size that
|
||||
will result in: |
||||
|
||||
4084 < CountOfClusters && CountOfClusters < 65525 |
||||
|
||||
The volume will then be FAT16. |
||||
|
||||
If you are formatting an SD card on OS X or Linux, be sure to use the first
|
||||
partition. Format this partition with a cluster count in above range. |
||||
|
||||
\section References References |
||||
|
||||
The Arduino site: |
||||
|
||||
http://www.arduino.cc/
|
||||
|
||||
For more information about FAT file systems see: |
||||
|
||||
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
|
||||
For information about using SD cards as SPI devices see: |
||||
|
||||
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
|
||||
The ATmega328 datasheet: |
||||
|
||||
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
|
||||
|
||||
|
||||
*/
|
@ -0,0 +1,418 @@ |
||||
/* Arduino Fat16 Library
|
||||
* Copyright (C) 2009 by William Greiman |
||||
* |
||||
* This file is part of the Arduino Fat16 Library |
||||
* |
||||
* This Library is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#ifndef FatStructs_h |
||||
#define FatStructs_h |
||||
/**
|
||||
* \file |
||||
* FAT file structures |
||||
*/ |
||||
/*
|
||||
* mostly from Microsoft document fatgen103.doc |
||||
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
*/ |
||||
//------------------------------------------------------------------------------
|
||||
/** Value for byte 510 of boot block or MBR */ |
||||
uint8_t const BOOTSIG0 = 0X55; |
||||
/** Value for byte 511 of boot block or MBR */ |
||||
uint8_t const BOOTSIG1 = 0XAA; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct partitionTable |
||||
* \brief MBR partition table entry |
||||
* |
||||
* A partition table entry for a MBR formatted storage device. |
||||
* The MBR partition table has four entries. |
||||
*/ |
||||
struct partitionTable { |
||||
/**
|
||||
* Boot Indicator . Indicates whether the volume is the active |
||||
* partition. Legal values include: 0X00. Do not use for booting. |
||||
* 0X80 Active partition. |
||||
*/ |
||||
uint8_t boot; |
||||
/**
|
||||
* Head part of Cylinder-head-sector address of the first block in |
||||
* the partition. Legal values are 0-255. Only used in old PC BIOS. |
||||
*/ |
||||
uint8_t beginHead; |
||||
/**
|
||||
* Sector part of Cylinder-head-sector address of the first block in |
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS. |
||||
*/ |
||||
unsigned beginSector : 6; |
||||
/** High bits cylinder for first block in partition. */ |
||||
unsigned beginCylinderHigh : 2; |
||||
/**
|
||||
* Combine beginCylinderLow with beginCylinderHigh. Legal values |
||||
* are 0-1023. Only used in old PC BIOS. |
||||
*/ |
||||
uint8_t beginCylinderLow; |
||||
/**
|
||||
* Partition type. See defines that begin with PART_TYPE_ for |
||||
* some Microsoft partition types. |
||||
*/ |
||||
uint8_t type; |
||||
/**
|
||||
* head part of cylinder-head-sector address of the last sector in the |
||||
* partition. Legal values are 0-255. Only used in old PC BIOS. |
||||
*/ |
||||
uint8_t endHead; |
||||
/**
|
||||
* Sector part of cylinder-head-sector address of the last sector in |
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS. |
||||
*/ |
||||
unsigned endSector : 6; |
||||
/** High bits of end cylinder */ |
||||
unsigned endCylinderHigh : 2; |
||||
/**
|
||||
* Combine endCylinderLow with endCylinderHigh. Legal values |
||||
* are 0-1023. Only used in old PC BIOS. |
||||
*/ |
||||
uint8_t endCylinderLow; |
||||
/** Logical block address of the first block in the partition. */ |
||||
uint32_t firstSector; |
||||
/** Length of the partition, in blocks. */ |
||||
uint32_t totalSectors; |
||||
}; |
||||
/** Type name for partitionTable */ |
||||
typedef struct partitionTable part_t; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct masterBootRecord |
||||
* |
||||
* \brief Master Boot Record |
||||
* |
||||
* The first block of a storage device that is formatted with a MBR. |
||||
*/ |
||||
struct masterBootRecord { |
||||
/** Code Area for master boot program. */ |
||||
uint8_t codeArea[440]; |
||||
/** Optional WindowsNT disk signature. May contain more boot code. */ |
||||
uint32_t diskSignature; |
||||
/** Usually zero but may be more boot code. */ |
||||
uint16_t usuallyZero; |
||||
/** Partition tables. */ |
||||
part_t part[4]; |
||||
/** First MBR signature byte. Must be 0X55 */ |
||||
uint8_t mbrSig0; |
||||
/** Second MBR signature byte. Must be 0XAA */ |
||||
uint8_t mbrSig1; |
||||
}; |
||||
/** Type name for masterBootRecord */ |
||||
typedef struct masterBootRecord mbr_t; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct biosParmBlock |
||||
* |
||||
* \brief BIOS parameter block |
||||
*
|
||||
* The BIOS parameter block describes the physical layout of a FAT volume. |
||||
*/ |
||||
struct biosParmBlock { |
||||
/**
|
||||
* Count of bytes per sector. This value may take on only the |
||||
* following values: 512, 1024, 2048 or 4096 |
||||
*/ |
||||
uint16_t bytesPerSector; |
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a |
||||
* power of 2 that is greater than 0. The legal values are |
||||
* 1, 2, 4, 8, 16, 32, 64, and 128. |
||||
*/ |
||||
uint8_t sectorsPerCluster; |
||||
/**
|
||||
* Number of sectors before the first FAT. |
||||
* This value must not be zero. |
||||
*/ |
||||
uint16_t reservedSectorCount; |
||||
/** The count of FAT data structures on the volume. This field should
|
||||
* always contain the value 2 for any FAT volume of any type. |
||||
*/ |
||||
uint8_t fatCount; |
||||
/**
|
||||
* For FAT12 and FAT16 volumes, this field contains the count of |
||||
* 32-byte directory entries in the root directory. For FAT32 volumes, |
||||
* this field must be set to 0. For FAT12 and FAT16 volumes, this |
||||
* value should always specify a count that when multiplied by 32 |
||||
* results in a multiple of bytesPerSector. FAT16 volumes should |
||||
* use the value 512. |
||||
*/ |
||||
uint16_t rootDirEntryCount; |
||||
/**
|
||||
* This field is the old 16-bit total count of sectors on the volume. |
||||
* This count includes the count of all sectors in all four regions |
||||
* of the volume. This field can be 0; if it is 0, then totalSectors32 |
||||
* must be non-zero. For FAT32 volumes, this field must be 0. For |
||||
* FAT12 and FAT16 volumes, this field contains the sector count, and |
||||
* totalSectors32 is 0 if the total sector count fits |
||||
* (is less than 0x10000). |
||||
*/ |
||||
uint16_t totalSectors16; |
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is |
||||
* no longer usually used for anything. 0xF8 is the standard value |
||||
* for fixed (non-removable) media. For removable media, 0xF0 is |
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF. |
||||
*/ |
||||
uint8_t mediaType; |
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes. |
||||
* On FAT32 volumes this field must be 0, and sectorsPerFat32 |
||||
* contains the FAT size count. |
||||
*/ |
||||
uint16_t sectorsPerFat16; |
||||
/** Sectors per track for interrupt 0x13. Not used otherwise. */ |
||||
uint16_t sectorsPerTrtack; |
||||
/** Number of heads for interrupt 0x13. Not used otherwise. */ |
||||
uint16_t headCount; |
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this |
||||
* FAT volume. This field is generally only relevant for media |
||||
* visible on interrupt 0x13. |
||||
*/ |
||||
uint32_t hidddenSectors; |
||||
/**
|
||||
* This field is the new 32-bit total count of sectors on the volume. |
||||
* This count includes the count of all sectors in all four regions |
||||
* of the volume. This field can be 0; if it is 0, then |
||||
* totalSectors16 must be non-zero. |
||||
*/ |
||||
uint32_t totalSectors32; |
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT32 volumes. |
||||
*/ |
||||
uint32_t sectorsPerFat32; |
||||
/**
|
||||
* This field is only defined for FAT32 media and does not exist on |
||||
* FAT12 and FAT16 media. |
||||
* Bits 0-3 -- Zero-based number of active FAT. |
||||
* Only valid if mirroring is disabled. |
||||
* Bits 4-6 -- Reserved. |
||||
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. |
||||
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3. |
||||
* Bits 8-15 -- Reserved. |
||||
*/ |
||||
uint16_t fat32Flags; |
||||
/**
|
||||
* FAT32 version. High byte is major revision number. |
||||
* Low byte is minor revision number. Only 0.0 define. |
||||
*/ |
||||
uint16_t fat32Version; |
||||
/**
|
||||
* Cluster number of the first cluster of the root directory for FAT32. |
||||
* This usually 2 but not required to be 2. |
||||
*/ |
||||
uint32_t fat32RootCluster; |
||||
/**
|
||||
* Sector number of FSINFO structure in the reserved area of the |
||||
* FAT32 volume. Usually 1. |
||||
*/ |
||||
uint16_t fat32FSInfo; |
||||
/**
|
||||
* If non-zero, indicates the sector number in the reserved area |
||||
* of the volume of a copy of the boot record. Usually 6. |
||||
* No value other than 6 is recommended. |
||||
*/ |
||||
uint16_t fat32BackBootBlock; |
||||
/**
|
||||
* Reserved for future expansion. Code that formats FAT32 volumes |
||||
* should always set all of the bytes of this field to 0. |
||||
*/ |
||||
uint8_t fat32Reserved[12]; |
||||
}; |
||||
/** Type name for biosParmBlock */ |
||||
typedef struct biosParmBlock bpb_t; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct fat32BootSector |
||||
* |
||||
* \brief Boot sector for a FAT16 or FAT32 volume. |
||||
*
|
||||
*/
|
||||
struct fat32BootSector { |
||||
/** X86 jmp to boot program */ |
||||
uint8_t jmpToBootCode[3]; |
||||
/** informational only - don't depend on it */ |
||||
char oemName[8]; |
||||
/** BIOS Parameter Block */ |
||||
bpb_t bpb; |
||||
/** for int0x13 use value 0X80 for hard drive */ |
||||
uint8_t driveNumber; |
||||
/** used by Windows NT - should be zero for FAT */ |
||||
uint8_t reserved1; |
||||
/** 0X29 if next three fields are valid */ |
||||
uint8_t bootSignature; |
||||
/** usually generated by combining date and time */ |
||||
uint32_t volumeSerialNumber; |
||||
/** should match volume label in root dir */ |
||||
char volumeLabel[11]; |
||||
/** informational only - don't depend on it */ |
||||
char fileSystemType[8]; |
||||
/** X86 boot code */ |
||||
uint8_t bootCode[420]; |
||||
/** must be 0X55 */ |
||||
uint8_t bootSectorSig0; |
||||
/** must be 0XAA */ |
||||
uint8_t bootSectorSig1; |
||||
}; |
||||
//------------------------------------------------------------------------------
|
||||
// End Of Chain values for FAT entries
|
||||
/** FAT16 end of chain value used by Microsoft. */ |
||||
uint16_t const FAT16EOC = 0XFFFF; |
||||
/** Minimum value for FAT16 EOC. Use to test for EOC. */ |
||||
uint16_t const FAT16EOC_MIN = 0XFFF8; |
||||
/** FAT32 end of chain value used by Microsoft. */ |
||||
uint32_t const FAT32EOC = 0X0FFFFFFF; |
||||
/** Minimum value for FAT32 EOC. Use to test for EOC. */ |
||||
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8; |
||||
/** Mask a for FAT32 entry. Entries are 28 bits. */ |
||||
uint32_t const FAT32MASK = 0X0FFFFFFF; |
||||
|
||||
/** Type name for fat32BootSector */ |
||||
typedef struct fat32BootSector fbs_t; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct directoryEntry |
||||
* \brief FAT short directory entry |
||||
* |
||||
* Short means short 8.3 name, not the entry size. |
||||
*
|
||||
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the |
||||
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||
* 16-bit word): |
||||
*
|
||||
* Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||
* inclusive (1980-2107). |
||||
*
|
||||
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. |
||||
* |
||||
* Bits 0-4: Day of month, valid value range 1-31 inclusive. |
||||
* |
||||
* Time Format. A FAT directory entry time stamp is a 16-bit field that has |
||||
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||
* 16-bit word, bit 15 is the MSB of the 16-bit word). |
||||
*
|
||||
* Bits 11-15: Hours, valid value range 0-23 inclusive. |
||||
*
|
||||
* Bits 5-10: Minutes, valid value range 0-59 inclusive. |
||||
*
|
||||
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). |
||||
*
|
||||
* The valid time range is from Midnight 00:00:00 to 23:59:58. |
||||
*/ |
||||
struct directoryEntry { |
||||
/**
|
||||
* Short 8.3 name. |
||||
* The first eight bytes contain the file name with blank fill. |
||||
* The last three bytes contain the file extension with blank fill. |
||||
*/ |
||||
uint8_t name[11]; |
||||
/** Entry attributes.
|
||||
* |
||||
* The upper two bits of the attribute byte are reserved and should |
||||
* always be set to 0 when a file is created and never modified or |
||||
* looked at after that. See defines that begin with DIR_ATT_. |
||||
*/ |
||||
uint8_t attributes; |
||||
/**
|
||||
* Reserved for use by Windows NT. Set value to 0 when a file is |
||||
* created and never modify or look at it after that. |
||||
*/ |
||||
uint8_t reservedNT; |
||||
/**
|
||||
* The granularity of the seconds part of creationTime is 2 seconds |
||||
* so this field is a count of tenths of a second and its valid |
||||
* value range is 0-199 inclusive. (WHG note - seems to be hundredths) |
||||
*/ |
||||
uint8_t creationTimeTenths; |
||||
/** Time file was created. */ |
||||
uint16_t creationTime; |
||||
/** Date file was created. */ |
||||
uint16_t creationDate; |
||||
/**
|
||||
* Last access date. Note that there is no last access time, only |
||||
* a date. This is the date of last read or write. In the case of |
||||
* a write, this should be set to the same date as lastWriteDate. |
||||
*/ |
||||
uint16_t lastAccessDate; |
||||
/**
|
||||
* High word of this entry's first cluster number (always 0 for a |
||||
* FAT12 or FAT16 volume). |
||||
*/ |
||||
uint16_t firstClusterHigh; |
||||
/** Time of last write. File creation is considered a write. */ |
||||
uint16_t lastWriteTime; |
||||
/** Date of last write. File creation is considered a write. */ |
||||
uint16_t lastWriteDate; |
||||
/** Low word of this entry's first cluster number. */ |
||||
uint16_t firstClusterLow; |
||||
/** 32-bit unsigned holding this file's size in bytes. */ |
||||
uint32_t fileSize; |
||||
}; |
||||
//------------------------------------------------------------------------------
|
||||
// Definitions for directory entries
|
||||
//
|
||||
/** Type name for directoryEntry */ |
||||
typedef struct directoryEntry dir_t; |
||||
/** escape for name[0] = 0XE5 */ |
||||
uint8_t const DIR_NAME_0XE5 = 0X05; |
||||
/** name[0] value for entry that is free after being "deleted" */ |
||||
uint8_t const DIR_NAME_DELETED = 0XE5; |
||||
/** name[0] value for entry that is free and no allocated entries follow */ |
||||
uint8_t const DIR_NAME_FREE = 0X00; |
||||
/** file is read-only */ |
||||
uint8_t const DIR_ATT_READ_ONLY = 0X01; |
||||
/** File should hidden in directory listings */ |
||||
uint8_t const DIR_ATT_HIDDEN = 0X02; |
||||
/** Entry is for a system file */ |
||||
uint8_t const DIR_ATT_SYSTEM = 0X04; |
||||
/** Directory entry contains the volume label */ |
||||
uint8_t const DIR_ATT_VOLUME_ID = 0X08; |
||||
/** Entry is for a directory */ |
||||
uint8_t const DIR_ATT_DIRECTORY = 0X10; |
||||
/** Old DOS archive bit for backup support */ |
||||
uint8_t const DIR_ATT_ARCHIVE = 0X20; |
||||
/** Test value for long name entry. Test is
|
||||
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */ |
||||
uint8_t const DIR_ATT_LONG_NAME = 0X0F; |
||||
/** Test mask for long name entry */ |
||||
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F; |
||||
/** defined attribute bits */ |
||||
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F; |
||||
/** Directory entry is part of a long name */ |
||||
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) { |
||||
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME; |
||||
} |
||||
/** Mask for file/subdirectory tests */ |
||||
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY); |
||||
/** Directory entry is for a file */ |
||||
static inline uint8_t DIR_IS_FILE(const dir_t* dir) { |
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0; |
||||
} |
||||
/** Directory entry is for a subdirectory */ |
||||
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) { |
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY; |
||||
} |
||||
/** Directory entry is for a file or subdirectory */ |
||||
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { |
||||
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; |
||||
} |
||||
#endif // FatStructs_h
|
@ -0,0 +1,277 @@ |
||||
/* Arduino FAT16 Library
|
||||
* Copyright (C) 2008 by William Greiman |
||||
* |
||||
* This file is part of the Arduino FAT16 Library |
||||
* |
||||
* This Library is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#include <avr/pgmspace.h> |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
#include <Fat16Config.h> |
||||
#include <SdCard.h> |
||||
//------------------------------------------------------------------------------
|
||||
// r1 status values
|
||||
uint8_t const R1_READY_STATE = 0; |
||||
uint8_t const R1_IDLE_STATE = 1; |
||||
// start data token for read or write
|
||||
uint8_t const DATA_START_BLOCK = 0XFE; |
||||
// data response tokens for write block
|
||||
uint8_t const DATA_RES_MASK = 0X1F; |
||||
uint8_t const DATA_RES_ACCEPTED = 0X05; |
||||
uint8_t const DATA_RES_CRC_ERROR = 0X0B; |
||||
uint8_t const DATA_RES_WRITE_ERROR = 0X0D; |
||||
//
|
||||
// stop compiler from inlining where speed optimization is not required
|
||||
#define STATIC_NOINLINE static __attribute__((noinline)) |
||||
//------------------------------------------------------------------------------
|
||||
// SPI static functions
|
||||
//
|
||||
// clock byte in
|
||||
STATIC_NOINLINE uint8_t spiRec(void) { |
||||
SPDR = 0xff; |
||||
while (!(SPSR & (1 << SPIF))); |
||||
return SPDR; |
||||
} |
||||
// clock byte out
|
||||
STATIC_NOINLINE void spiSend(uint8_t b) { |
||||
SPDR = b; |
||||
while (!(SPSR & (1 << SPIF))); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
// wait for card to go not busy
|
||||
// return false if timeout
|
||||
static uint8_t waitForToken(uint8_t token, uint16_t timeoutMillis) { |
||||
uint16_t t0 = millis(); |
||||
while (spiRec() != token) { |
||||
if (((uint16_t)millis() - t0) > timeoutMillis) return false; |
||||
} |
||||
return true; |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdCard::cardCommand(uint8_t cmd, uint32_t arg) { |
||||
uint8_t r1; |
||||
|
||||
// select card
|
||||
chipSelectLow(); |
||||
|
||||
// wait if busy
|
||||
waitForToken(0XFF, SD_COMMAND_TIMEOUT); |
||||
|
||||
// send command
|
||||
spiSend(cmd | 0x40); |
||||
|
||||
// send argument
|
||||
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); |
||||
|
||||
// send CRC - must send valid CRC for CMD0
|
||||
spiSend(cmd == CMD0 ? 0x95 : 0XFF); |
||||
|
||||
// wait for not busy
|
||||
for (uint8_t retry = 0; (0X80 & (r1 = spiRec())) && retry != 0XFF; retry++); |
||||
return r1; |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdCard::cardAcmd(uint8_t cmd, uint32_t arg) { |
||||
cardCommand(CMD55, 0); |
||||
return cardCommand(cmd, arg); |
||||
} |
||||
//==============================================================================
|
||||
// SdCard member functions
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Determine the size of a standard SD flash memory card |
||||
* \return The number of 512 byte data blocks in the card |
||||
*/ |
||||
uint32_t SdCard::cardSize(void) { |
||||
uint16_t c_size; |
||||
csd_t csd; |
||||
if (!readReg(CMD9, &csd)) return 0; |
||||
uint8_t read_bl_len = csd.read_bl_len; |
||||
c_size = (csd.c_size_high << 10) | (csd.c_size_mid << 2) | csd.c_size_low; |
||||
uint8_t c_size_mult = (csd.c_size_mult_high << 1) | csd.c_size_mult_low; |
||||
return (uint32_t)(c_size+1) << (c_size_mult + read_bl_len - 7); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
void SdCard::chipSelectHigh(void) { |
||||
digitalWrite(chipSelectPin_, HIGH); |
||||
// make sure MISO goes high impedance
|
||||
spiSend(0XFF); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
void SdCard::chipSelectLow(void) { |
||||
// Enable SPI, Master, clock rate F_CPU/4
|
||||
SPCR = (1 << SPE) | (1 << MSTR); |
||||
|
||||
// Doubled Clock Frequency to F_CPU/2 unless speed_ is nonzero
|
||||
if (!speed_) SPSR |= (1 << SPI2X); |
||||
|
||||
digitalWrite(chipSelectPin_, LOW); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
void SdCard::error(uint8_t code, uint8_t data) { |
||||
errorData = data; |
||||
error(code); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
void SdCard::error(uint8_t code) { |
||||
errorCode = code; |
||||
chipSelectHigh(); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Initialize a SD flash memory card. |
||||
* |
||||
* \param[in] speed Set SPI Frequency to F_CPU/2 if speed = 0 or F_CPU/4 |
||||
* if speed = 1. |
||||
* \param[in] chipSelectPin SD chip select pin number. |
||||
* |
||||
* \return The value one, true, is returned for success and |
||||
* the value zero, false, is returned for failure. |
||||
* |
||||
*/ |
||||
uint8_t SdCard::init(uint8_t speed, uint8_t chipSelectPin) { |
||||
if (speed > 1) { |
||||
error(SD_ERROR_SPI_SPEED); |
||||
return false; |
||||
} |
||||
speed_ = speed; |
||||
chipSelectPin_ = chipSelectPin; |
||||
errorCode = 0; |
||||
uint8_t r; |
||||
// 16-bit init start time allows over a minute
|
||||
uint16_t t0 = (uint16_t)millis(); |
||||
|
||||
pinMode(chipSelectPin_, OUTPUT); |
||||
digitalWrite(chipSelectPin_, HIGH); |
||||
pinMode(SPI_MISO_PIN, INPUT); |
||||
pinMode(SPI_SS_PIN, OUTPUT); |
||||
pinMode(SPI_MOSI_PIN, OUTPUT); |
||||
pinMode(SPI_SCK_PIN, OUTPUT); |
||||
|
||||
// Enable SPI, Master, clock rate F_CPU/128
|
||||
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); |
||||
|
||||
// must supply min of 74 clock cycles with CS high.
|
||||
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); |
||||
digitalWrite(chipSelectPin_, LOW); |
||||
|
||||
// command to go idle in SPI mode
|
||||
while ((r = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { |
||||
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { |
||||
error(SD_ERROR_CMD0, r); |
||||
return false; |
||||
} |
||||
} |
||||
// start initialization and wait for completed initialization
|
||||
while ((r = cardAcmd(ACMD41, 0)) != R1_READY_STATE) { |
||||
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { |
||||
error(SD_ERROR_ACMD41, r); |
||||
return false; |
||||
} |
||||
} |
||||
chipSelectHigh(); |
||||
return true; |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Reads a 512 byte block from a storage device. |
||||
* |
||||
* \param[in] blockNumber Logical block to be read. |
||||
* \param[out] dst Pointer to the location that will receive the data. |
||||
* \return The value one, true, is returned for success and |
||||
* the value zero, false, is returned for failure. |
||||
*/ |
||||
uint8_t SdCard::readBlock(uint32_t blockNumber, uint8_t* dst) { |
||||
if (cardCommand(CMD17, blockNumber << 9)) { |
||||
error(SD_ERROR_CMD17); |
||||
return false; |
||||
} |
||||
return readTransfer(dst, 512); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdCard::readReg(uint8_t cmd, void* buf) { |
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf); |
||||
if (cardCommand(cmd, 0)) { |
||||
chipSelectHigh(); |
||||
return false; |
||||
} |
||||
return readTransfer(dst, 16); |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdCard::readTransfer(uint8_t* dst, uint16_t count) { |
||||
// wait for start of data
|
||||
if (!waitForToken(DATA_START_BLOCK, SD_READ_TIMEOUT)) { |
||||
error(SD_ERROR_READ_TIMEOUT); |
||||
} |
||||
// start first spi transfer
|
||||
SPDR = 0XFF; |
||||
for (uint16_t i = 0; i < count; i++) { |
||||
while (!(SPSR & (1 << SPIF))); |
||||
dst[i] = SPDR; |
||||
SPDR = 0XFF; |
||||
} |
||||
// wait for first CRC byte
|
||||
while (!(SPSR & (1 << SPIF))); |
||||
spiRec(); // second CRC byte
|
||||
chipSelectHigh(); |
||||
return true; |
||||
} |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Writes a 512 byte block to a storage device. |
||||
* |
||||
* \param[in] blockNumber Logical block to be written. |
||||
* \param[in] src Pointer to the location of the data to be written. |
||||
* \return The value one, true, is returned for success and |
||||
* the value zero, false, is returned for failure. |
||||
*/ |
||||
uint8_t SdCard::writeBlock(uint32_t blockNumber, const uint8_t* src) { |
||||
uint32_t address = blockNumber << 9; |
||||
#if SD_PROTECT_BLOCK_ZERO |
||||
// don't allow write to first block
|
||||
if (address == 0) { |
||||
error(SD_ERROR_BLOCK_ZERO_WRITE); |
||||
return false; |
||||
} |
||||
#endif // SD_PROTECT_BLOCK_ZERO
|
||||
if (cardCommand(CMD24, address)) { |
||||
error(SD_ERROR_CMD24); |
||||
return false; |
||||
} |
||||
// optimize write loop
|
||||
SPDR = DATA_START_BLOCK; |
||||
for (uint16_t i = 0; i < 512; i++) { |
||||
while (!(SPSR & (1 << SPIF))); |
||||
SPDR = src[i]; |
||||
} |
||||
while (!(SPSR & (1 << SPIF))); // wait for last data byte
|
||||
spiSend(0xFF); // dummy crc
|
||||
spiSend(0xFF); // dummy crc
|
||||
|
||||
// get write response
|
||||
uint8_t r1 = spiRec(); |
||||
if ((r1 & DATA_RES_MASK) != DATA_RES_ACCEPTED) { |
||||
error(SD_ERROR_WRITE_RESPONSE, r1); |
||||
return false; |
||||
} |
||||
// wait for card to complete write programming
|
||||
if (!waitForToken(0XFF, SD_WRITE_TIMEOUT)) { |
||||
error(SD_ERROR_WRITE_TIMEOUT); |
||||
} |
||||
chipSelectHigh(); |
||||
return true; |
||||
} |
@ -0,0 +1,192 @@ |
||||
/* Arduino FAT16 Library
|
||||
* Copyright (C) 2008 by William Greiman |
||||
* |
||||
* This file is part of the Arduino FAT16 Library |
||||
* |
||||
* This Library is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#ifndef SdCard_h |
||||
#define SdCard_h |
||||
/**
|
||||
* \file |
||||
* SdCard class |
||||
*/ |
||||
#include <SdInfo.h> |
||||
//------------------------------------------------------------------------------
|
||||
// Warning only SD_CHIP_SELECT_PIN, the SD card select pin, may be redefined.
|
||||
// define hardware SPI pins
|
||||
#if defined(__AVR_ATmega168__)\ |
||||
||defined(__AVR_ATmega168P__)\
|
||||
||defined(__AVR_ATmega328P__) |
||||
// 168 and 328 Arduinos
|
||||
/** Slave Select pin */ |
||||
uint8_t const SPI_SS_PIN = 10; |
||||
/** Master Out Slave In pin */ |
||||
uint8_t const SPI_MOSI_PIN = 11; |
||||
/** Master In Slave Out pin */ |
||||
uint8_t const SPI_MISO_PIN = 12; |
||||
/** Serial Clock */ |
||||
uint8_t const SPI_SCK_PIN = 13; |
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega1280__)\ |
||||
|| defined(__AVR_ATmega2560__) |
||||
// pins for Arduino Mega
|
||||
uint8_t const SPI_SS_PIN = 53; |
||||
uint8_t const SPI_MOSI_PIN = 51; |
||||
uint8_t const SPI_MISO_PIN = 50; |
||||
uint8_t const SPI_SCK_PIN = 52; |
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega644P__)\ |
||||
|| defined(__AVR_ATmega644__)\
|
||||
|| defined(__AVR_ATmega1284P__) |
||||
// pins for Sanguino
|
||||
uint8_t const SPI_SS_PIN = 4; |
||||
uint8_t const SPI_MOSI_PIN = 5; |
||||
uint8_t const SPI_MISO_PIN = 6; |
||||
uint8_t const SPI_SCK_PIN = 7; |
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega32U4__) |
||||
// pins for Teensy 2.0
|
||||
uint8_t const SPI_SS_PIN = 0; |
||||
uint8_t const SPI_MOSI_PIN = 2; |
||||
uint8_t const SPI_MISO_PIN = 3; |
||||
uint8_t const SPI_SCK_PIN = 1; |
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_AT90USB646__)\ |
||||
|| defined(__AVR_AT90USB1286__) |
||||
// pins for Teensy++ 1.0 & 2.0
|
||||
uint8_t const SPI_SS_PIN = 20; |
||||
uint8_t const SPI_MOSI_PIN = 22; |
||||
uint8_t const SPI_MISO_PIN = 23; |
||||
uint8_t const SPI_SCK_PIN = 21; |
||||
//------------------------------------------------------------------------------
|
||||
#else // SPI pins
|
||||
#error unknown CPU |
||||
#endif // SPI pins
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* SD Chip Select pin |
||||
* |
||||
* Warning if this pin is redefined the hardware SS pin will be enabled |
||||
* as an output by init(). An avr processor will not function as an SPI |
||||
* master unless SS is set to output mode. |
||||
* |
||||
* For example to set SD_CHIP_SELECT_PIN to 8 for the SparkFun microSD shield: |
||||
* uint8_t const SD_CHIP_SELECT_PIN = 8; |
||||
* |
||||
* The default chip select pin for the SD card is SS. |
||||
*/ |
||||
uint8_t const SD_CHIP_SELECT_PIN = SPI_SS_PIN; |
||||
//------------------------------------------------------------------------------
|
||||
/** command timeout ms */ |
||||
uint16_t const SD_COMMAND_TIMEOUT = 300; |
||||
/** init timeout ms */ |
||||
uint16_t const SD_INIT_TIMEOUT = 2000; |
||||
/** read timeout ms */ |
||||
uint16_t const SD_READ_TIMEOUT = 300; |
||||
/** write timeout ms */ |
||||
uint16_t const SD_WRITE_TIMEOUT = 600; |
||||
//------------------------------------------------------------------------------
|
||||
// error codes
|
||||
/** Card did not go into SPI mode */ |
||||
uint8_t const SD_ERROR_CMD0 = 1; |
||||
/** Card did not go ready */ |
||||
uint8_t const SD_ERROR_ACMD41 = 2; |
||||
/** Write command not accepted */ |
||||
uint8_t const SD_ERROR_CMD24 = 3; |
||||
/** Read command not accepted */ |
||||
uint8_t const SD_ERROR_CMD17 = 4; |
||||
/** timeout waiting for read data */ |
||||
uint8_t const SD_ERROR_READ_TIMEOUT = 5; |
||||
/** write error occurred */ |
||||
uint8_t const SD_ERROR_WRITE_RESPONSE = 6; |
||||
/** timeout waiting for write status */ |
||||
uint8_t const SD_ERROR_WRITE_TIMEOUT = 7; |
||||
/** attempt to write block zero */ |
||||
uint8_t const SD_ERROR_BLOCK_ZERO_WRITE = 8; |
||||
/** card returned an error to a CMD13 status check after a write */ |
||||
uint8_t const SD_ERROR_WRITE_PROGRAMMING = 9; |
||||
/** invalid SPI speed in init() call */ |
||||
uint8_t const SD_ERROR_SPI_SPEED = 10; |
||||
//------------------------------------------------------------------------------
|
||||
// SD command codes
|
||||
/** SEND OPERATING CONDITIONS */ |
||||
uint8_t const ACMD41 = 0X29; |
||||
/** GO_IDLE_STATE - init card in spi mode if CS low */ |
||||
uint8_t const CMD0 = 0X00; |
||||
/** SEND_CSD - Card Specific Data */ |
||||
uint8_t const CMD9 = 0X09; |
||||
/** SEND_CID - Card IDentification */ |
||||
uint8_t const CMD10 = 0X0A; |
||||
/** SEND_STATUS - read the card status register */ |
||||
uint8_t const CMD13 = 0X0D; |
||||
/** READ_BLOCK */ |
||||
uint8_t const CMD17 = 0X11; |
||||
/** WRITE_BLOCK */ |
||||
uint8_t const CMD24 = 0X18; |
||||
/** APP_CMD - escape for application specific command */ |
||||
uint8_t const CMD55 = 0X37; |
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdCard |
||||
* \brief Hardware access class for SD flash cards |
||||
* |
||||
* Supports raw access to a standard SD flash memory card. |
||||
* |
||||
*/ |
||||
class SdCard { |
||||
public: |
||||
/** Code for a SD error. See SdCard.h for definitions. */ |
||||
uint8_t errorCode; |
||||
/** Data that may be helpful in determining the cause of an error */ |
||||
uint8_t errorData; |
||||
uint32_t cardSize(void); |
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip |
||||
* select pin. See SdCard::init(uint8_t sckRateID, uint8_t chipSelectPin). |
||||
*/ |
||||
uint8_t init(void) { |
||||
return init(0, SD_CHIP_SELECT_PIN); |
||||
} |
||||
/**
|
||||
* Initialize an SD flash memory card with the selected SPI clock rate |
||||
* and the default SD chip select pin. |
||||
* See SdCard::init(uint8_t slow, uint8_t chipSelectPin). |
||||
*/ |
||||
uint8_t init(uint8_t speed) { |
||||
return init(speed, SD_CHIP_SELECT_PIN); |
||||
} |
||||
uint8_t init(uint8_t speed, uint8_t chipselectPin); |
||||
uint8_t readBlock(uint32_t block, uint8_t* dst); |
||||
/** Read the CID register which contains info about the card.
|
||||
* This includes Manufacturer ID, OEM ID, product name, version, |
||||
* serial number, and manufacturing date. */ |
||||
uint8_t readCID(cid_t* cid) { |
||||
return readReg(CMD10, cid); |
||||
} |
||||
uint8_t writeBlock(uint32_t block, const uint8_t* src); |
||||
private: |
||||
uint8_t cardAcmd(uint8_t cmd, uint32_t arg); |
||||
uint8_t cardCommand(uint8_t cmd, uint32_t arg); |
||||
uint8_t chipSelectPin_; |
||||
uint8_t speed_; |
||||
void chipSelectHigh(void); |
||||
void chipSelectLow(void); |
||||
void error(uint8_t code, uint8_t data); |
||||
void error(uint8_t code); |
||||
uint8_t readReg(uint8_t cmd, void* buf); |
||||
uint8_t readTransfer(uint8_t* dst, uint16_t count); |
||||
}; |
||||
#endif // SdCard_h
|
@ -0,0 +1,117 @@ |
||||
/* Arduino FAT16 Library
|
||||
* Copyright (C) 2008 by William Greiman |
||||
* |
||||
* This file is part of the Arduino FAT16 Library |
||||
* |
||||
* This Library is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This Library is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with the Arduino Fat16 Library. If not, see |
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#ifndef SdInfo_h |
||||
#define SdInfo_h |
||||
#include <stdint.h> |
||||
// Based on the document:
|
||||
//
|
||||
// SD Specifications
|
||||
// Part 1
|
||||
// Physical Layer
|
||||
// Simplified Specification
|
||||
// Version 2.00
|
||||
// September 25, 2006
|
||||
//
|
||||
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
//
|
||||
// Card IDentification (CID) register
|
||||
typedef struct CID { |
||||
// byte 0
|
||||
uint8_t mid; // Manufacturer ID
|
||||
// byte 1-2
|
||||
char oid[2]; // OEM/Application ID
|
||||
// byte 3-7
|
||||
char pnm[5]; // Product name
|
||||
// byte 8
|
||||
unsigned prv_m : 4; // Product revision n.m
|
||||
unsigned prv_n : 4; |
||||
// byte 9-12
|
||||
uint32_t psn; // Product serial number
|
||||
// byte 13
|
||||
unsigned mdt_year_high : 4; // Manufacturing date
|
||||
unsigned reserved : 4; |
||||
// byte 14
|
||||
unsigned mdt_month : 4; |
||||
unsigned mdt_year_low :4; |
||||
// byte 15
|
||||
unsigned always1 : 1; |
||||
unsigned crc : 7; |
||||
}cid_t; |
||||
// Card-Specific Data register
|
||||
typedef struct CSD { |
||||
// byte 0
|
||||
unsigned reserved1 : 6; |
||||
unsigned csd_ver : 2; |
||||
// byte 1
|
||||
uint8_t taac; |
||||
// byte 2
|
||||
uint8_t nsac; |
||||
// byte 3
|
||||
uint8_t tran_speed; |
||||
// byte 4
|
||||
uint8_t ccc_high; |
||||
// byte 5
|
||||
unsigned read_bl_len : 4; |
||||
unsigned ccc_low : 4; |
||||
// byte 6
|
||||
unsigned c_size_high : 2; |
||||
unsigned reserved2 : 2; |
||||
unsigned dsr_imp : 1; |
||||
unsigned read_blk_misalign :1; |
||||
unsigned write_blk_misalign : 1; |
||||
unsigned read_bl_partial : 1; |
||||
// byte 7
|
||||
uint8_t c_size_mid; |
||||
// byte 8
|
||||
unsigned vdd_r_curr_max : 3; |
||||
unsigned vdd_r_curr_min : 3; |
||||
unsigned c_size_low :2; |
||||
// byte 9
|
||||
unsigned c_size_mult_high : 2; |
||||
unsigned vdd_w_cur_max : 3; |
||||
unsigned vdd_w_curr_min : 3; |
||||
// byte 10
|
||||
unsigned sector_size_high : 6; |
||||
unsigned erase_blk_en : 1; |
||||
unsigned c_size_mult_low : 1; |
||||
// byte 11
|
||||
unsigned wp_grp_size : 7; |
||||
unsigned sector_size_low : 1; |
||||
// byte 12
|
||||
unsigned write_bl_len_high : 2; |
||||
unsigned r2w_factor : 3; |
||||
unsigned reserved3 : 2; |
||||
unsigned wp_grp_enable : 1; |
||||
// byte 13
|
||||
unsigned reserved4 : 5; |
||||
unsigned write_partial : 1; |
||||
unsigned write_bl_len_low : 2; |
||||
// byte 14
|
||||
unsigned reserved5: 2; |
||||
unsigned file_format : 2; |
||||
unsigned tmp_write_protect : 1; |
||||
unsigned perm_write_protect : 1; |
||||
unsigned copy : 1; |
||||
unsigned file_format_grp : 1; |
||||
// byte 15
|
||||
unsigned always1 : 1; |
||||
unsigned crc : 7; |
||||
}csd_t; |
||||
#endif // SdInfo_h
|
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> |
||||
* SPI Master library for arduino. |
||||
* |
||||
* This file is free software; you can redistribute it and/or modify |
||||
* it under the terms of either the GNU General Public License version 2 |
||||
* or the GNU Lesser General Public License version 2.1, both as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
#include "pins_arduino.h" |
||||
#include "SPI.h" |
||||
|
||||
SPIClass SPI; |
||||
|
||||
void SPIClass::begin() { |
||||
|
||||
// Set SS to high so a connected chip will be "deselected" by default
|
||||
digitalWrite(SS, HIGH); |
||||
|
||||
// When the SS pin is set as OUTPUT, it can be used as
|
||||
// a general purpose output port (it doesn't influence
|
||||
// SPI operations).
|
||||
pinMode(SS, OUTPUT); |
||||
|
||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
||||
// automatically switches to Slave, so the data direction of
|
||||
// the SS pin MUST be kept as OUTPUT.
|
||||
SPCR |= _BV(MSTR); |
||||
SPCR |= _BV(SPE); |
||||
|
||||
// Set direction register for SCK and MOSI pin.
|
||||
// MISO pin automatically overrides to INPUT.
|
||||
// By doing this AFTER enabling SPI, we avoid accidentally
|
||||
// clocking in a single bit since the lines go directly
|
||||
// from "input" to SPI control.
|
||||
// http://code.google.com/p/arduino/issues/detail?id=888
|
||||
pinMode(SCK, OUTPUT); |
||||
pinMode(MOSI, OUTPUT); |
||||
} |
||||
|
||||
|
||||
void SPIClass::end() { |
||||
SPCR &= ~_BV(SPE); |
||||
} |
||||
|
||||
void SPIClass::setBitOrder(uint8_t bitOrder) |
||||
{ |
||||
if(bitOrder == LSBFIRST) { |
||||
SPCR |= _BV(DORD); |
||||
} else { |
||||
SPCR &= ~(_BV(DORD)); |
||||
} |
||||
} |
||||
|
||||
void SPIClass::setDataMode(uint8_t mode) |
||||
{ |
||||
SPCR = (SPCR & ~SPI_MODE_MASK) | mode; |
||||
} |
||||
|
||||
void SPIClass::setClockDivider(uint8_t rate) |
||||
{ |
||||
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); |
||||
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); |
||||
} |
||||
|
@ -0,0 +1,70 @@ |
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> |
||||
* SPI Master library for arduino. |
||||
* |
||||
* This file is free software; you can redistribute it and/or modify |
||||
* it under the terms of either the GNU General Public License version 2 |
||||
* or the GNU Lesser General Public License version 2.1, both as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
#ifndef _SPI_H_INCLUDED |
||||
#define _SPI_H_INCLUDED |
||||
|
||||
#include <stdio.h> |
||||
#include <Arduino.h> |
||||
#include <avr/pgmspace.h> |
||||
|
||||
#define SPI_CLOCK_DIV4 0x00 |
||||
#define SPI_CLOCK_DIV16 0x01 |
||||
#define SPI_CLOCK_DIV64 0x02 |
||||
#define SPI_CLOCK_DIV128 0x03 |
||||
#define SPI_CLOCK_DIV2 0x04 |
||||
#define SPI_CLOCK_DIV8 0x05 |
||||
#define SPI_CLOCK_DIV32 0x06 |
||||
//#define SPI_CLOCK_DIV64 0x07
|
||||
|
||||
#define SPI_MODE0 0x00 |
||||
#define SPI_MODE1 0x04 |
||||
#define SPI_MODE2 0x08 |
||||
#define SPI_MODE3 0x0C |
||||
|
||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
|
||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
|
||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
|
||||
|
||||
class SPIClass { |
||||
public: |
||||
inline static byte transfer(byte _data); |
||||
|
||||
// SPI Configuration methods
|
||||
|
||||
inline static void attachInterrupt(); |
||||
inline static void detachInterrupt(); // Default
|
||||
|
||||
static void begin(); // Default
|
||||
static void end(); |
||||
|
||||
static void setBitOrder(uint8_t); |
||||
static void setDataMode(uint8_t); |
||||
static void setClockDivider(uint8_t); |
||||
}; |
||||
|
||||
extern SPIClass SPI; |
||||
|
||||
byte SPIClass::transfer(byte _data) { |
||||
SPDR = _data; |
||||
while (!(SPSR & _BV(SPIF))) |
||||
; |
||||
return SPDR; |
||||
} |
||||
|
||||
void SPIClass::attachInterrupt() { |
||||
SPCR |= _BV(SPIE); |
||||
} |
||||
|
||||
void SPIClass::detachInterrupt() { |
||||
SPCR &= ~_BV(SPIE); |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,94 @@ |
||||
/*******************************************************************************
|
||||
SerialCommand - An Arduino library to tokenize and parse commands received over |
||||
a serial port.
|
||||
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com> |
||||
http://awtfy.com
|
||||
|
||||
Version 20131021A.
|
||||
|
||||
Version History: |
||||
May 11 2011 - Initial version |
||||
May 13 2011 - Prevent overwriting bounds of SerialCommandCallback[] array in addCommand() |
||||
defaultHandler() for non-matching commands |
||||
Mar 2012 - Some const char * changes to make compiler happier about deprecated warnings.
|
||||
Arduino 1.0 compatibility (Arduino.h header)
|
||||
Oct 2013 - SerialCommand object can be created using a SoftwareSerial object, for SoftwareSerial |
||||
support. Requires #include <SoftwareSerial.h> in your sketch even if you don't use
|
||||
a SoftwareSerial port in the project. sigh. See Example Sketch for usage.
|
||||
Oct 2013 - Conditional compilation for the SoftwareSerial support, in case you really, really |
||||
hate it and want it removed.
|
||||
|
||||
This library is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU Lesser General Public |
||||
License as published by the Free Software Foundation; either |
||||
version 2.1 of the License, or (at your option) any later version. |
||||
|
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
Lesser General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU Lesser General Public |
||||
License along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
***********************************************************************************/ |
||||
#ifndef SerialCommand_h |
||||
#define SerialCommand_h |
||||
|
||||
|
||||
#include "Arduino.h" |
||||
|
||||
|
||||
// If you want to use SerialCommand with the hardware serial port only, and want to disable
|
||||
// SoftwareSerial support, and thus don't have to use "#include <SoftwareSerial.h>" in your
|
||||
// sketches, then uncomment this define for SERIALCOMMAND_HARDWAREONLY, and comment out the
|
||||
// corresponding #undef line.
|
||||
//
|
||||
// You don't have to use SoftwareSerial features if this is not defined, you can still only use
|
||||
// the Hardware serial port, just that this way lets you get out of having to include
|
||||
// the SoftwareSerial.h header.
|
||||
#define SERIALCOMMAND_HARDWAREONLY 1 |
||||
//#undef SERIALCOMMAND_HARDWAREONLY
|
||||
|
||||
|
||||
|
||||
#include <string.h> |
||||
|
||||
|
||||
#define SERIALCOMMANDBUFFER 16 |
||||
#define MAXSERIALCOMMANDS 10 |
||||
#define MAXDELIMETER 2 |
||||
|
||||
#define SERIALCOMMANDDEBUG 1 |
||||
#undef SERIALCOMMANDDEBUG // Comment this out to run the library in debug mode (verbose messages)
|
||||
|
||||
class SerialCommand |
||||
{ |
||||
public: |
||||
SerialCommand(); // Constructor
|
||||
|
||||
void clearBuffer(); // Sets the command buffer to all '\0' (nulls)
|
||||
char *next(); // returns pointer to next token found in command buffer (for getting arguments to commands)
|
||||
void readSerial(); // Main entry point.
|
||||
void addCommand(const char *, void(*)()); // Add commands to processing dictionary
|
||||
void addDefaultHandler(void (*function)()); // A handler to call when no valid command received.
|
||||
|
||||
private: |
||||
char inChar; // A character read from the serial stream
|
||||
char buffer[SERIALCOMMANDBUFFER]; // Buffer of stored characters while waiting for terminator character
|
||||
int bufPos; // Current position in the buffer
|
||||
char delim[MAXDELIMETER]; // null-terminated list of character to be used as delimeters for tokenizing (default " ")
|
||||
char term; // Character that signals end of command (default '\r')
|
||||
char *token; // Returned token from the command buffer as returned by strtok_r
|
||||
char *last; // State variable used by strtok_r during processing
|
||||
typedef struct _callback { |
||||
char command[SERIALCOMMANDBUFFER]; |
||||
void (*function)(); |
||||
} SerialCommandCallback; // Data structure to hold Command/Handler function key-value pairs
|
||||
int numCommand; |
||||
SerialCommandCallback CommandList[MAXSERIALCOMMANDS]; // Actual definition for command/handler array
|
||||
void (*defaultHandler)(); // Pointer to the default handler function
|
||||
int usingSoftwareSerial; // Used as boolean to see if we're using SoftwareSerial object or not
|
||||
}; |
||||
|
||||
#endif //SerialCommand_h
|
@ -0,0 +1,118 @@ |
||||
/*
|
||||
* prescaler.h |
||||
* |
||||
* Provides useful tools to manage the clock prescaler and issues |
||||
* related to time and delays. Allows to easily set the prescaler |
||||
* and get access to its value. Also provides alternative functions |
||||
* to the millis() and delay() functions. |
||||
* |
||||
* (c) 2008 Sofian Audry | info(@)sofianaudry(.)com |
||||
* http://sofianaudry.com
|
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#ifndef PRESCALER_INC |
||||
#define PRESCALER_INC |
||||
|
||||
#include "Arduino.h" |
||||
|
||||
/**
|
||||
* Prescaler division |
||||
*/ |
||||
#define CLOCK_PRESCALER_1 (0x0) |
||||
#define CLOCK_PRESCALER_2 (0x1) |
||||
#define CLOCK_PRESCALER_4 (0x2) |
||||
#define CLOCK_PRESCALER_8 (0x3) |
||||
#define CLOCK_PRESCALER_16 (0x4) |
||||
#define CLOCK_PRESCALER_32 (0x5) |
||||
#define CLOCK_PRESCALER_64 (0x6) |
||||
#define CLOCK_PRESCALER_128 (0x7) |
||||
#define CLOCK_PRESCALER_256 (0x8) |
||||
|
||||
// Initialize global variable.
|
||||
static uint8_t __clock_prescaler = (CLKPR & (_BV(CLKPS0) | _BV(CLKPS1) | _BV(CLKPS2) | _BV(CLKPS3))); |
||||
|
||||
inline void setClockPrescaler(uint8_t clockPrescaler) { |
||||
if (clockPrescaler <= CLOCK_PRESCALER_256) { |
||||
// Disable interrupts.
|
||||
uint8_t oldSREG = SREG; |
||||
cli(); |
||||
|
||||
// Enable change.
|
||||
CLKPR = _BV(CLKPCE); // write the CLKPCE bit to one and all the other to zero
|
||||
|
||||
// Change clock division.
|
||||
CLKPR = clockPrescaler; // write the CLKPS0..3 bits while writing the CLKPE bit to zero
|
||||
|
||||
// Copy for fast access.
|
||||
__clock_prescaler = clockPrescaler; |
||||
|
||||
// Recopy interrupt register.
|
||||
SREG = oldSREG; |
||||
} |
||||
} |
||||
|
||||
inline uint8_t getClockPrescaler() { |
||||
return (__clock_prescaler); |
||||
} |
||||
|
||||
inline uint16_t getClockDivisionFactor() { |
||||
return ((uint16_t)(1 << __clock_prescaler)); |
||||
} |
||||
|
||||
/**
|
||||
* Time in milliseconds. |
||||
* |
||||
* NOTE: This is the equivalent of the millis() function but it readjusts it according |
||||
* to the current clock division. As such, be careful of how you make use of it, in |
||||
* particular remember it will be wrong if the clock division factor is changed during the |
||||
* course of computation. Remember that you can reset the overflow counter by calling the |
||||
* init() function from wiring.h. |
||||
*/ |
||||
inline unsigned long trueMillis() |
||||
{ |
||||
return millis() * getClockDivisionFactor(); |
||||
} |
||||
|
||||
inline unsigned long trueMicros() { |
||||
return micros() * getClockDivisionFactor(); |
||||
} |
||||
|
||||
// Waits for #ms# milliseconds.
|
||||
// NOTE: Please see comment above.
|
||||
inline void trueDelay(unsigned long ms) |
||||
{ |
||||
unsigned long start = trueMillis(); |
||||
while (trueMillis() - start < ms); |
||||
} |
||||
|
||||
/**
|
||||
* Rescales given delay time according to division factor. Should be called before a call |
||||
* to delay(). Insures compatibility with function using delay(). |
||||
* Example use: |
||||
* delay( rescaleDelay(1000) ); // equivalent to wait(1000)
|
||||
*/ |
||||
inline unsigned long rescaleDuration(unsigned long d) { |
||||
return (d / getClockDivisionFactor()); |
||||
} |
||||
|
||||
/**
|
||||
* Rescales given time (in milliseconds or microseconds) according to division factor. Should |
||||
* be called |
||||
*/ |
||||
inline unsigned long rescaleTime(unsigned long t) { |
||||
return (t * getClockDivisionFactor()); |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,148 @@ |
||||
/* Rotary encoder handler for arduino. v1.1
|
||||
* |
||||
* Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3. |
||||
* Contact: bb@cactii.net |
||||
* |
||||
* A typical mechanical rotary encoder emits a two bit gray code |
||||
* on 3 output pins. Every step in the output (often accompanied |
||||
* by a physical 'click') generates a specific sequence of output |
||||
* codes on the pins. |
||||
* |
||||
* There are 3 pins used for the rotary encoding - one common and |
||||
* two 'bit' pins. |
||||
* |
||||
* The following is the typical sequence of code on the output when |
||||
* moving from one step to the next: |
||||
* |
||||
* Position Bit1 Bit2 |
||||
* ---------------------- |
||||
* Step1 0 0 |
||||
* 1/4 1 0 |
||||
* 1/2 1 1 |
||||
* 3/4 0 1 |
||||
* Step2 0 0 |
||||
* |
||||
* From this table, we can see that when moving from one 'click' to |
||||
* the next, there are 4 changes in the output code. |
||||
* |
||||
* - From an initial 0 - 0, Bit1 goes high, Bit0 stays low. |
||||
* - Then both bits are high, halfway through the step. |
||||
* - Then Bit1 goes low, but Bit2 stays high. |
||||
* - Finally at the end of the step, both bits return to 0. |
||||
* |
||||
* Detecting the direction is easy - the table simply goes in the other |
||||
* direction (read up instead of down). |
||||
* |
||||
* To decode this, we use a simple state machine. Every time the output |
||||
* code changes, it follows state, until finally a full steps worth of |
||||
* code is received (in the correct order). At the final 0-0, it returns |
||||
* a value indicating a step in one direction or the other. |
||||
* |
||||
* It's also possible to use 'half-step' mode. This just emits an event |
||||
* at both the 0-0 and 1-1 positions. This might be useful for some |
||||
* encoders where you want to detect all positions. |
||||
* |
||||
* If an invalid state happens (for example we go from '0-1' straight |
||||
* to '1-0'), the state machine resets to the start until 0-0 and the |
||||
* next valid codes occur. |
||||
* |
||||
* The biggest advantage of using a state machine over other algorithms |
||||
* is that this has inherent debounce built in. Other algorithms emit spurious |
||||
* output with switch bounce, but this one will simply flip between |
||||
* sub-states until the bounce settles, then continue along the state |
||||
* machine. |
||||
* A side effect of debounce is that fast rotations can cause steps to |
||||
* be skipped. By not requiring debounce, fast rotations can be accurately |
||||
* measured. |
||||
* Another advantage is the ability to properly handle bad state, such |
||||
* as due to EMI, etc. |
||||
* It is also a lot simpler than others - a static state table and less |
||||
* than 10 lines of logic. |
||||
*/ |
||||
|
||||
#include "Arduino.h" |
||||
#include "rotary.h" |
||||
|
||||
/*
|
||||
* The below state table has, for each state (row), the new state |
||||
* to set based on the next encoder output. From left to right in, |
||||
* the table, the encoder outputs are 00, 01, 10, 11, and the value |
||||
* in that position is the new state to set. |
||||
*/ |
||||
|
||||
#define R_START 0x0 |
||||
|
||||
#ifdef HALF_STEP |
||||
// Use the half-step state table (emits a code at 00 and 11)
|
||||
#define R_CCW_BEGIN 0x1 |
||||
#define R_CW_BEGIN 0x2 |
||||
#define R_START_M 0x3 |
||||
#define R_CW_BEGIN_M 0x4 |
||||
#define R_CCW_BEGIN_M 0x5 |
||||
const unsigned char ttable[6][4] = { |
||||
// R_START (00)
|
||||
{R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, |
||||
// R_CCW_BEGIN
|
||||
{R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, |
||||
// R_CW_BEGIN
|
||||
{R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, |
||||
// R_START_M (11)
|
||||
{R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, |
||||
// R_CW_BEGIN_M
|
||||
{R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, |
||||
// R_CCW_BEGIN_M
|
||||
{R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW}, |
||||
}; |
||||
#else |
||||
// Use the full-step state table (emits a code at 00 only)
|
||||
#define R_CW_FINAL 0x1 |
||||
#define R_CW_BEGIN 0x2 |
||||
#define R_CW_NEXT 0x3 |
||||
#define R_CCW_BEGIN 0x4 |
||||
#define R_CCW_FINAL 0x5 |
||||
#define R_CCW_NEXT 0x6 |
||||
|
||||
const unsigned char ttable[7][4] = { |
||||
// R_START
|
||||
{R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, |
||||
// R_CW_FINAL
|
||||
{R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, |
||||
// R_CW_BEGIN
|
||||
{R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, |
||||
// R_CW_NEXT
|
||||
{R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, |
||||
// R_CCW_BEGIN
|
||||
{R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, |
||||
// R_CCW_FINAL
|
||||
{R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, |
||||
// R_CCW_NEXT
|
||||
{R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START}, |
||||
}; |
||||
#endif |
||||
|
||||
/*
|
||||
* Constructor. Each arg is the pin number for each encoder contact. |
||||
*/ |
||||
Rotary::Rotary(char _pin1, char _pin2) { |
||||
// Assign variables.
|
||||
pin1 = _pin1; |
||||
pin2 = _pin2; |
||||
// Set pins to input.
|
||||
pinMode(pin1, INPUT); |
||||
pinMode(pin2, INPUT); |
||||
#ifdef ENABLE_PULLUPS |
||||
digitalWrite(pin1, HIGH); |
||||
digitalWrite(pin2, HIGH); |
||||
#endif |
||||
// Initialise state.
|
||||
state = R_START; |
||||
} |
||||
|
||||
unsigned char Rotary::process() { |
||||
// Grab state of input pins.
|
||||
unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1); |
||||
// Determine new state from the pins and state table.
|
||||
state = ttable[state & 0xf][pinstate]; |
||||
// Return emit bits, ie the generated event.
|
||||
return state & 0x30; |
||||
} |
@ -0,0 +1,37 @@ |
||||
/*
|
||||
* Rotary encoder library for Arduino. |
||||
*/ |
||||
|
||||
#ifndef rotary_h |
||||
#define rotary_h |
||||
|
||||
#include "Arduino.h" |
||||
|
||||
// Enable this to emit codes twice per step.
|
||||
//#define HALF_STEP
|
||||
|
||||
// Enable weak pullups
|
||||
#define ENABLE_PULLUPS |
||||
|
||||
// Values returned by 'process'
|
||||
// No complete step yet.
|
||||
#define DIR_NONE 0x0 |
||||
// Clockwise step.
|
||||
#define DIR_CW 0x10 |
||||
// Anti-clockwise step.
|
||||
#define DIR_CCW 0x20 |
||||
|
||||
class Rotary |
||||
{ |
||||
public: |
||||
Rotary(char, char); |
||||
// Process pin(s)
|
||||
unsigned char process(); |
||||
private: |
||||
unsigned char state; |
||||
unsigned char pin1; |
||||
unsigned char pin2; |
||||
}; |
||||
|
||||
#endif |
||||
|
Loading…
Reference in new issue