Compare commits
2 Commits
b40cc843a2
...
0ebe9c4fd7
Author | SHA1 | Date |
---|---|---|
Peter Babič | 0ebe9c4fd7 | 4 years ago |
Peter Babič | e555d1e3cf | 4 years ago |
@ -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 |
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue