From bc9c387332dc16290f1c1c180eabae0d33eec8fe Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 19:12:32 +0100 Subject: [PATCH 001/222] Update library.properties --- libraries/Wire/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index ad2d9e26..737ced11 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -3,8 +3,8 @@ version=1.0 author=Intel maintainer=Intel email=dave@emutex.com -sentence=Arduino 101 Wire library -paragraph=Supports Arduino 101 Arduino Breakout board +sentence=This library allows you to communicate with I2C and Two Wire Interface devices. +paragraph=This library is compatible with Curie Core. It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line). url=http://makers.intel.com architectures=arc32 core-dependencies=arduino (>=1.6.3) From 7905133b686bf5dcc0112b828a9d8128ddf6ee8e Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 19:24:32 +0100 Subject: [PATCH 002/222] Update library.properties --- libraries/CurieSoftwareSerial/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/CurieSoftwareSerial/library.properties b/libraries/CurieSoftwareSerial/library.properties index bab0c5ee..140ec10c 100644 --- a/libraries/CurieSoftwareSerial/library.properties +++ b/libraries/CurieSoftwareSerial/library.properties @@ -2,8 +2,8 @@ name=CurieSoftwareSerial version=0.1 author=Intel maintainer=Intel -sentence=SoftwareSerial Library port for Arduino101 -paragraph= +sentence=Enables serial communication on any digital pin, port for Curie Core. +paragraph=The CurieSoftwareSerial library has been developed to allow serial communication on any digital pin of the board, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. category=Communication url=http://www.arduino.cc/en/Reference/SoftwareSerial architectures=arc32 From fda58303cb959000bb8d04855f5b11838423d15d Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 19:35:08 +0100 Subject: [PATCH 003/222] Update library.properties --- libraries/SPI/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties index b8e91184..7791be93 100644 --- a/libraries/SPI/library.properties +++ b/libraries/SPI/library.properties @@ -2,8 +2,8 @@ name=SPI version=1.0 author=Intel/Emutex maintainer=Intel/Emutex -sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino 101 boards. -paragraph= +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For Curie Core boards. +paragraph=SPI is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. It uses three lines common to all devices (MISO, MOSI and SCK) and one specific for each device. category=Communication url=http://www.arduino.cc/en/Reference/SPI architectures=arc32 From 5bb196cdd961a0fb54129d1fcf2fc99778ab0914 Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 19:58:12 +0100 Subject: [PATCH 004/222] Update library.properties --- libraries/CurieEEPROM/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/CurieEEPROM/library.properties b/libraries/CurieEEPROM/library.properties index 6319a77e..0f3c1e2b 100644 --- a/libraries/CurieEEPROM/library.properties +++ b/libraries/CurieEEPROM/library.properties @@ -3,7 +3,7 @@ version=1.0 author=Intel maintainer=Intel sentence=Enables reading and writing to OTP flash area of Curie -paragraph= +paragraph=This library allows to read and write data on a memory type and area that keeps its content also when the board is powered off. category=Data Storage url=http://www.arduino.cc/en/Reference/EEPROM architectures=arc32 From 3d019ed2cebf9034e37cda961d16b08042d8f731 Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 21:34:23 +0100 Subject: [PATCH 005/222] Update library.properties --- libraries/SD/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties index a41f9279..0bb170cb 100644 --- a/libraries/SD/library.properties +++ b/libraries/SD/library.properties @@ -2,8 +2,8 @@ name=SD version=1.0.6 author=Arduino, SparkFun maintainer=Arduino -sentence=Enables reading and writing on SD cards. For all Arduino boards. -paragraph=Once an SD memory card is connected to the SPI interfare of the Arduino board you are enabled to create files and read/write on them. You can also move through directories on the SD card. +sentence=Enables reading and writing on SD cards. For all boards. +paragraph=Once an SD memory card is connected to the SPI interface of the board you can create files and read/write on them. You can also move through directories on the SD card. category=Data Storage url=http://www.arduino.cc/en/Reference/SD architectures=arc32 From 72b85b2bdb884a995620e3aeb66d518844b0746a Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 21:39:55 +0100 Subject: [PATCH 006/222] Update library.properties --- libraries/Servo/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Servo/library.properties b/libraries/Servo/library.properties index c9920297..ecd68f67 100644 --- a/libraries/Servo/library.properties +++ b/libraries/Servo/library.properties @@ -2,7 +2,7 @@ name=Servo version=1.0 author=Intel/Emutex maintainer=Intel/Emutex -sentence=Arduino 101 Servo Library +sentence=Servo Library for Curie Core. paragraph=This library can control a great number of servos.
It makes careful use of timers: the library can control 12 servos using only 1 timer. category=Device Control url=http://www.arduino.cc/en/Reference/Servo From c4a20140569016649b4333ef6c349c8041827164 Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 21:55:23 +0100 Subject: [PATCH 007/222] Update library.properties --- libraries/CurieBLE/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/CurieBLE/library.properties b/libraries/CurieBLE/library.properties index 2839e5cc..4b17054d 100644 --- a/libraries/CurieBLE/library.properties +++ b/libraries/CurieBLE/library.properties @@ -2,8 +2,8 @@ name=CurieBLE version=1.0 author=Emutex maintainer=Emutex -sentence=Bluetooth Low Energy API for Intel Curie BLE device. -paragraph= +sentence=Library to manage the Bluetooth Low Energy module with Curie Core boards. +paragraph=Using this library, it is possible to use BLE features to communicate and interact with other devices like smartphones and tablets. This library enables multiple types of functionalities through a number of different classes. category=Communication url= architectures=arc32 From 1f3899a7cabd71ae9fbda7f721a117614587adaa Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Thu, 3 Mar 2016 22:29:38 +0100 Subject: [PATCH 008/222] Update library.properties --- libraries/CurieIMU/library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/CurieIMU/library.properties b/libraries/CurieIMU/library.properties index 9e82e98a..0861d835 100644 --- a/libraries/CurieIMU/library.properties +++ b/libraries/CurieIMU/library.properties @@ -2,8 +2,8 @@ name=CurieIMU version=1.0 author=Emutex maintainer=Emutex -sentence=BMI160 6DOF IMU Sensor Library for Intel Curie -paragraph=Provides access to 3-axis Accelerometer and Gyroscope data from the BMI160 IMU incorporated on Intel Curie modules +sentence=IMU Sensor Library for BMI160 on Curie Core boards. +paragraph=Provides access to Accelerometer and Gyroscope data from the IMU, together with the full control of the features available like step count, tap, shock and freefall detection. category=Sensors url= architectures=arc32 From f02410e9bf138f48243b62853b44c9b797ea01e9 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Wed, 24 Feb 2016 20:04:14 -0800 Subject: [PATCH 009/222] Fixing sketch size calculation (text + ctors + rodata) Signed-off-by: Brian Baltz --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 3bd09687..2b2a2258 100644 --- a/platform.txt +++ b/platform.txt @@ -85,7 +85,7 @@ recipe.output.save_file={build.project_name}.{build.variant}.hex ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" -recipe.size.regex=Total\s+([0-9]+).* +recipe.size.regex=^(?:text|ctors|rodata|datas)\s+([0-9]+).* # Arc Uploader/Programmers tools # ------------------- From c7b30f4c627ad20b5cdbc621803afa76fba61bfd Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Tue, 8 Mar 2016 07:07:43 -0800 Subject: [PATCH 010/222] Decrease max sketch size to 155,648 bytes Signed-off-by: Brian Baltz --- boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards.txt b/boards.txt index 22603043..903f7c17 100644 --- a/boards.txt +++ b/boards.txt @@ -10,7 +10,7 @@ arduino_101.vid.0x2A03.warning=Uncertified arduino_101.upload.tool=arduino101load arduino_101.upload.protocol=script -arduino_101.upload.maximum_size=196608 +arduino_101.upload.maximum_size=155648 arduino_101.upload.use_1200bps_touch=true arduino_101.upload.wait_for_upload_port=false arduino_101.upload.native_usb=false From 17eac79d76b721eb116179aa87f0e3627add4927 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Tue, 8 Mar 2016 10:54:11 -0800 Subject: [PATCH 011/222] Fix Klockwork issues in CurieEEPROM #142 -Also fixes issue of not being able to rewrite the last 3/4 of the EEPROM area --- libraries/CurieEEPROM/src/CurieEEPROM.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/libraries/CurieEEPROM/src/CurieEEPROM.cpp b/libraries/CurieEEPROM/src/CurieEEPROM.cpp index bb0c8060..3127f18f 100644 --- a/libraries/CurieEEPROM/src/CurieEEPROM.cpp +++ b/libraries/CurieEEPROM/src/CurieEEPROM.cpp @@ -48,18 +48,13 @@ void CurieEEPROM::write(uint32_t address, uint32_t data) address*=sizeof(uint32_t); uint32_t rom_wr_ctrl = 0; - //make sure address is valid - if((address > 0x7FC) || (address%4)) - { - return; - } //check if address is available for writing a new value. If not erase the whole 2K block and re-write the rest of the data if(currentValue!=0xFFFFFFFF) { //read entire 2k of data - uint32_t blockdata[EEPROM_SIZE/4]; - for(int i = 0; i < EEPROM_SIZE/4; i++) + uint32_t blockdata[EEPROM_SIZE]; + for(int i = 0; i < EEPROM_SIZE; i++) { blockdata[i] = read(i*sizeof(uint32_t)); } @@ -72,7 +67,7 @@ void CurieEEPROM::write(uint32_t address, uint32_t data) clear(); //write back all data with update data on passed address - for(int i = 0; i < EEPROM_SIZE/4; i++) + for(int i = 0; i < EEPROM_SIZE; i++) { //store data into ROM_WR_DATA register *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; @@ -115,8 +110,8 @@ void CurieEEPROM::write8(uint32_t address, uint8_t data) if(currentValue!=0xFF) { //read entire 2k of data - uint32_t blockdata[EEPROM_SIZE/4]; - for(int i = 0; i < EEPROM_SIZE/4; i++) + uint32_t blockdata[EEPROM_SIZE]; + for(int i = 0; i < EEPROM_SIZE; i++) { blockdata[i] = read(i*sizeof(uint32_t)); } @@ -135,7 +130,7 @@ void CurieEEPROM::write8(uint32_t address, uint8_t data) clear(); //write back all data with update data on passed address - for(int i = 0; i < EEPROM_SIZE/4; i++) + for(int i = 0; i < EEPROM_SIZE; i++) { //store data into ROM_WR_DATA register *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; From 40d3fb07d98db264dc1f2b0c2b5a3057359a721d Mon Sep 17 00:00:00 2001 From: "Bradford H. Needham" Date: Tue, 8 Mar 2016 20:35:51 -0800 Subject: [PATCH 012/222] Added Eddystone-URL support: added setAdvertisedServiceData() to support BLE Service Data; changed Incomplete to Complete Service UUID list code in Advertising initialization, required by Eddystone-URL protocol; added (for debugging) getAdvertisingLength() and getAdvertising() to enable a Sketch viewing the Advertizing packet. --- libraries/CurieBLE/keywords.txt | 3 ++ libraries/CurieBLE/src/BLEPeripheral.cpp | 53 +++++++++++++++++++++++- libraries/CurieBLE/src/BLEPeripheral.h | 44 ++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/libraries/CurieBLE/keywords.txt b/libraries/CurieBLE/keywords.txt index ad168000..4598ecb2 100644 --- a/libraries/CurieBLE/keywords.txt +++ b/libraries/CurieBLE/keywords.txt @@ -49,7 +49,10 @@ written KEYWORD2 subscribed KEYWORD2 begin KEYWORD2 +getAdvertisingLength KEYWORD2 +getAdvertising KEYWORD2 setAdvertisedServiceUuid KEYWORD2 +setAdvertisedServiceData KEYWORD2 setLocalName KEYWORD2 setAppearance KEYWORD2 setConnectionInterval KEYWORD2 diff --git a/libraries/CurieBLE/src/BLEPeripheral.cpp b/libraries/CurieBLE/src/BLEPeripheral.cpp index 2ac52983..f1218bcd 100644 --- a/libraries/CurieBLE/src/BLEPeripheral.cpp +++ b/libraries/CurieBLE/src/BLEPeripheral.cpp @@ -47,6 +47,9 @@ BLEPeripheral::BLEPeripheral(void) : _state(BLE_PERIPH_STATE_NOT_READY), _advertise_service_uuid(NULL), _local_name(NULL), + _service_data_uuid(NULL), + _service_data(NULL), + _service_data_length(0), _appearance(0), _min_conn_interval(DEFAULT_MIN_CONN_INTERVAL), _max_conn_interval(DEFAULT_MAX_CONN_INTERVAL), @@ -136,6 +139,18 @@ BLEPeripheral::end() _stop(); } +uint8_t +BLEPeripheral::getAdvertisingLength() +{ + return _adv_data_len; +} + +uint8_t* +BLEPeripheral::getAdvertising() +{ + return _adv_data; +} + void BLEPeripheral::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { @@ -148,6 +163,14 @@ BLEPeripheral::setLocalName(const char* localName) _local_name = localName; } +void +BLEPeripheral::setAdvertisedServiceData(const char* serviceDataUuid, uint8_t* serviceData, uint8_t serviceDataLength) +{ + _service_data_uuid = serviceDataUuid; + _service_data = serviceData; + _service_data_length = serviceDataLength; +} + void BLEPeripheral::setDeviceName(const char deviceName[]) { @@ -294,7 +317,7 @@ BLEPeripheral::_advDataInit(void) if (BT_UUID16 == uuid.type) { uint8_t *adv_tmp = &_adv_data[_adv_data_len]; *adv_tmp++ = (1 + sizeof(uint16_t)); /* Segment data length */ - *adv_tmp++ = BLE_ADV_TYPE_INC_16_UUID; + *adv_tmp++ = BLE_ADV_TYPE_COMP_16_UUID; /* Needed for Eddystone */ UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); _adv_data_len += (2 + sizeof(uint16_t)); } else if (BT_UUID128 == uuid.type) { @@ -324,6 +347,34 @@ BLEPeripheral::_advDataInit(void) memcpy(adv_tmp, _local_name, calculated_len); _adv_data_len += calculated_len + 2; } + + if (_service_data) { + /* Add Service Data (if it will fit) */ + + BLEUuid bleUuid = BLEUuid(_service_data_uuid); + struct bt_uuid uuid = bleUuid.uuid(); + + /* A 128-bit Service Data UUID won't fit in an Advertising packet */ + if (BT_UUID16 != uuid.type) { + return; /* We support service data only for 16-bit service UUID */ + } + + uint8_t block_len = 1 + sizeof(uint16_t) + _service_data_length; + if (_adv_data_len + 1 + block_len > BLE_MAX_ADV_SIZE) { + return; // Service data block is too large. + } + + adv_tmp = &_adv_data[_adv_data_len]; + + *adv_tmp++ = block_len; + _adv_data_len++; + + *adv_tmp++ = BLE_ADV_TYPE_SERVICE_DATA_16_UUID; + UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); + memcpy(adv_tmp, _service_data, _service_data_length); + + _adv_data_len += block_len; + } } BleStatus diff --git a/libraries/CurieBLE/src/BLEPeripheral.h b/libraries/CurieBLE/src/BLEPeripheral.h index 9a5e9c34..054af330 100644 --- a/libraries/CurieBLE/src/BLEPeripheral.h +++ b/libraries/CurieBLE/src/BLEPeripheral.h @@ -55,6 +55,23 @@ class BLEPeripheral { */ virtual ~BLEPeripheral(void); + /** + * Return the number of bytes in the advertising block. + * Useful for debugging advertising problems. + * + * @note Call only after calling begin(). + */ + uint8_t getAdvertisingLength(); + + /** + * Returns a pointer to the advertising block + * of length getAdvertisingLength(). + * Useful for debugging advertising problems. + * + * @note Call only after calling begin(). + */ + uint8_t* getAdvertising(); + /** * Set the service UUID that the BLE Peripheral Device advertises * @@ -74,6 +91,30 @@ class BLEPeripheral { */ void setLocalName(const char* localName); + /** + * Set the Service Data that the BLE Peripheral Device advertises + * + * @param serviceDataUuid 16-bit Service UUID for this Service Data + * (in string form). Must match the UUID parameter + * of setAdvertisedServiceUuid(). To fit into BLE_MAX_ADV_SIZE, + * the UUID must be a 16-bit UUID. + * + * @param serviceData binary array of Service Data. + * + * @param serviceDataLength length (bytes) of serviceData[] + * + * @note the entire advertising packet must be no more than + * BLE_MAX_ADV_SIZE bytes, which is currently 31. + * This likely means that if you use Service Data + * there will not be room for a Local Name. + * + * @note if serviceDataUuid isn't 16-bits long, or if + * serviceDataLength won't fit in the advertising block, + * the service data will silently not be copied + * into the advertising block. + */ + void setAdvertisedServiceData(const char* serviceDataUuid, uint8_t* serviceData, uint8_t serviceDataLength); + /** * Set the device name for the BLE Peripheral Device * @@ -194,6 +235,9 @@ class BLEPeripheral { const char* _advertise_service_uuid; const char* _local_name; + const char* _service_data_uuid; + uint8_t* _service_data; + uint8_t _service_data_length; char _device_name[BLE_MAX_DEVICE_NAME+1]; uint16_t _appearance; uint16_t _min_conn_interval; From 98ee736fa2bb12e99d80bad866a9a298e0bc1c2e Mon Sep 17 00:00:00 2001 From: SimonePDA Date: Mon, 14 Mar 2016 18:01:40 +0100 Subject: [PATCH 013/222] Update CurieTimer1Interrupt.ino Changed the style of the code according to Arduino's Tutorials guidelines. --- .../CurieTimer1Interrupt.ino | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/libraries/CurieTimerOne/examples/CurieTimer1Interrupt/CurieTimer1Interrupt.ino b/libraries/CurieTimerOne/examples/CurieTimer1Interrupt/CurieTimer1Interrupt.ino index 28841fdf..30750399 100644 --- a/libraries/CurieTimerOne/examples/CurieTimer1Interrupt/CurieTimer1Interrupt.ino +++ b/libraries/CurieTimerOne/examples/CurieTimer1Interrupt/CurieTimer1Interrupt.ino @@ -1,31 +1,45 @@ -// -// Sketch: Timer1Interrupt.ino -// -// This sketch demonstrates the usage of the ARC Timer-1. It -// uses timer-1 to blink the onboard LED, pin 13, at different -// intervals (speed). -// +/* + Sketch: Timer1Interrupt.ino -#include "CurieTimerOne.h" + This sketch demonstrates the usage of the Curie Timer One Library. + It uses timer-1 to blink the onboard LED, pin 13, at different + intervals (speed) in four steps. + + You can see the time interval and the number of interrupt counted + in 10 seconds if you keep serial logging active, but this may require + a MASTER_RESET to reprogram the board. + + Blinking of the LED will start only when you open the Serial Monitor + unless you comment the "#define SERIAL_PORT_LOG_ENABLE 1"; don't + forget to uncomment "CurieTimerOne.restart(time);" -// Uncomment the following statement to enable logging on serial port. -// #define SERIAL_PORT_LOG_ENABLE 1 + created by Intel + Modified 14 March 2016 + by Simone Majocchi -const unsigned int oneSecInUsec = 1000000; // A second in mirco second unit. -unsigned int toggle = 0; + This example code is in the public domain. +*/ + +#include "CurieTimerOne.h" +// Comment the following statement to disable logging on serial port. +#define SERIAL_PORT_LOG_ENABLE 1 -void timedBlinkIsr() +const int oneSecInUsec = 1000000; // A second in mirco second unit. +bool toggle = 0; // The LED status toggle +int time; // the variable used to set the Timer + +void timedBlinkIsr() // callback function when interrupt is asserted { - digitalWrite(13, toggle ? HIGH : LOW); - toggle = (toggle + 1) & 0x01; + digitalWrite(13, toggle); + toggle = !toggle; // use NOT operator to invert toggle value } void setup() { #ifdef SERIAL_PORT_LOG_ENABLE Serial.begin(115200); - while(!Serial); + while (!Serial); // wait for the serial monitor to open #endif // Initialize pin 13 as an output - onboard LED. @@ -33,27 +47,25 @@ void setup() { } void loop() { - unsigned int i, time = oneSecInUsec; - - CurieTimerOne.start(time, &timedBlinkIsr); - for(i=0; i < 4; i++, time >>= 1) - { + for (int i = 1; i < 9; i = i * 2) { + // We set a blink rate of 1000000, 500000, 250000, 125000 microseconds + time = oneSecInUsec / i; // time is used to toggle the LED is divided by i + CurieTimerOne.start(time, &timedBlinkIsr); // set timer and callback #ifdef SERIAL_PORT_LOG_ENABLE Serial.print("The blink period: "); Serial.println(time); #endif - delay(10000); // 10 seconds + delay(10000); // 10 seconds of delay, regularly 'interrupted' by the timer interrupt #ifdef SERIAL_PORT_LOG_ENABLE Serial.print("Total number of ticks in 10 seconds: "); - Serial.println(CurieTimerOne.rdRstTickCount()); + Serial.println(CurieTimerOne.rdRstTickCount()); // Reads and Resets tick count Serial.println("----"); #endif - - CurieTimerOne.restart(time); + // Uncomment the following line if the serial logging is disabled + // CurieTimerOne.restart(time); // Restarts Timer } } - From 38a508e4552f88649cdd664babd0165673b7caa6 Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Tue, 8 Mar 2016 13:31:14 -0800 Subject: [PATCH 014/222] Jira-528. Make CurieTimerOne library to be compatible with the TimerOne library originated from Paul. Created methods that have the same name and functionalities as in the TimerOne library. --- .../CurieTimer1BlinkSpeed/blinkSpeed.ino | 30 ++++++ libraries/CurieTimerOne/keywords.txt | 30 +++--- libraries/CurieTimerOne/src/CurieTimerOne.cpp | 65 ++++++++----- libraries/CurieTimerOne/src/CurieTimerOne.h | 95 +++++++++++++++---- 4 files changed, 168 insertions(+), 52 deletions(-) create mode 100644 libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino diff --git a/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino b/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino new file mode 100644 index 00000000..04147cf0 --- /dev/null +++ b/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino @@ -0,0 +1,30 @@ +#include + +const int blinkPin = 13; + +void setup(void) +{ + CurieTimerOne.initialize(50000); + Serial.begin(9600); +} + +void loop(void) +{ + unsigned int range; + + Serial.println("PWM blink: low -> high duty cycle"); + + for (float dutyCycle = 5.0; dutyCycle <= 100.0; dutyCycle++) { + range = (dutyCycle / 100) * 1023; + CurieTimerOne.pwm(blinkPin, range); + delay(50); + } + + Serial.println("PWM blink: high -> low duty cycle"); + + for (float dutyCycle = 100.0; dutyCycle > 5.0; dutyCycle--) { + range = (dutyCycle / 100) * 1023; + CurieTimerOne.setPwmDuty(blinkPin, range); + delay(50); + } +} diff --git a/libraries/CurieTimerOne/keywords.txt b/libraries/CurieTimerOne/keywords.txt index bcf1d0a4..734a16df 100644 --- a/libraries/CurieTimerOne/keywords.txt +++ b/libraries/CurieTimerOne/keywords.txt @@ -11,18 +11,24 @@ CurieTimer KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -start KEYWORD2 -restart KEYWORD2 -kill KEYWORD2 -attachInterrupt KEYWORD2 -detachInterrupt KEYWORD2 -readTickCount KEYWORD2 -rdRstTickCount KEYWORD2 -pause KEYWORD2 -resume KEYWORD2 -pwmStart KEYWORD2 -pwmStop KEYWORD2 +initialize KEYWORD2 +setPeriod KEYWORD2 +start KEYWORD2 +stop KEYWORD2 +restart KEYWORD2 +resume KEYWORD2 +setPwmDuty KEYWORD2 +pwm KEYWORD2 +disablePwm KEYWORD2 +attachInterrupt KEYWORD2 +detachInterrupt KEYWORD2 +kill KEYWORD2 +readTickCount KEYWORD2 +rdRstTickCount KEYWORD2 +pause KEYWORD2 +pwmStart KEYWORD2 +pwmStop KEYWORD2 ####################################### # Instances (KEYWORD2) ####################################### -CurieTimerOne KEYWORD2 +CurieTimerOne KEYWORD2 diff --git a/libraries/CurieTimerOne/src/CurieTimerOne.cpp b/libraries/CurieTimerOne/src/CurieTimerOne.cpp index fe0d7653..5aa76385 100644 --- a/libraries/CurieTimerOne/src/CurieTimerOne.cpp +++ b/libraries/CurieTimerOne/src/CurieTimerOne.cpp @@ -50,25 +50,15 @@ static void timerOnePwmCbWrapper(void) } -CurieTimer::CurieTimer(const unsigned int timerNum) : +CurieTimer::CurieTimer() : tickCnt(0), currState(IDLE), userCB(NULL) { - if(timerNum == 0) { - timerCountAddr = ARC_V2_TMR0_COUNT; - timerControlAddr = ARC_V2_TMR0_CONTROL; - timerLimitAddr = ARC_V2_TMR0_LIMIT; - timerIrqNum = ARCV2_IRQ_TIMER0; - isrFuncPtr = NULL; - pwmCB = NULL; - } - else { - timerCountAddr = ARC_V2_TMR1_COUNT; - timerControlAddr = ARC_V2_TMR1_CONTROL; - timerLimitAddr = ARC_V2_TMR1_LIMIT; - timerIrqNum = ARCV2_IRQ_TIMER1; - isrFuncPtr = &timerOneIsrWrapper; - pwmCB = &timerOnePwmCbWrapper; - } + timerCountAddr = ARC_V2_TMR1_COUNT; + timerControlAddr = ARC_V2_TMR1_CONTROL; + timerLimitAddr = ARC_V2_TMR1_LIMIT; + timerIrqNum = ARCV2_IRQ_TIMER1; + isrFuncPtr = &timerOneIsrWrapper; + pwmCB = &timerOnePwmCbWrapper; } @@ -86,6 +76,7 @@ void CurieTimer::kill() tickCnt = 0; userCB = NULL; currState = IDLE; + pauseCntrl = pauseCount = pwmPin = dutyCycle = nonDutyCycle = periodInUsec = 0; } @@ -154,25 +145,26 @@ int CurieTimer::pwmStart(unsigned int outputPin, double dutyPercentage, unsigned unsigned int pwmPeriod; // Safe guard against periodUsec overflow when convert to hz. - if((periodUsec == 0) || (periodUsec >= MAX_PERIOD)) + if((periodUsec == 0) || (periodUsec >= MAX_PERIOD_USEC)) return -(INVALID_PERIOD); if((dutyPercentage < 0.0) || (dutyPercentage > 100.0)) return -(INVALID_DUTY_CYCLE); + periodInUsec = periodUsec; pwmPin = outputPin; pinMode(pwmPin, OUTPUT); if(dutyPercentage == 0.0) { - // If PWM is already running, reset the timer and set pin to LOW - kill(); + // If PWM is already running, pause to stop it from interfering, and set pin to LOW + pause(); digitalWrite(pwmPin, LOW); return SUCCESS; } if(dutyPercentage == 100.0) { - // If PWM is already running, reset the timer and set pin to HIGH - kill(); + // If PWM is already running, pause to stop it from interfering, and set pin to HIGH + pause(); digitalWrite(pwmPin, HIGH); return SUCCESS; } @@ -204,7 +196,7 @@ int CurieTimer::pwmStart(unsigned int outputPin, int dutyRange, unsigned int per if((dutyRange < 0) || (dutyRange > MAX_DUTY_RANGE)) return -(INVALID_DUTY_CYCLE); - return pwmStart(outputPin, ((double)dutyRange * 100.0)/(double)MAX_DUTY_RANGE, periodUsec); + return pwmStart(outputPin, ((double)dutyRange/(double)MAX_DUTY_RANGE) * 100.0, periodUsec); } @@ -224,6 +216,31 @@ inline void CurieTimer::pwmCallBack(void) } +// Method: setPeriod +// This method is for making this library backward compatible to the AVR +// TimerOne library. The routine changs the time period by pausing the timer +// and resume it with the new period. This is not timer re-initialization. + +void CurieTimer::setPeriod(unsigned long microseconds) +{ + unsigned int periodHz; + + if((microseconds == 0) || (microseconds > MAX_PERIOD_USEC)) + microseconds = 1000000; + + periodInUsec = microseconds; + periodHz = microseconds * HZ_USEC; + pause(); + + aux_reg_write(timerLimitAddr, periodHz); // Load Timer period + + if(pauseCount >= periodHz) + pauseCount = 0; + + resume(); +} + + // Method: init // Kick off the timer with a period, in Hz, provided. Initialize // timer to run in non-halt mode, enable timer interrupt. Always install @@ -232,7 +249,7 @@ inline void CurieTimer::pwmCallBack(void) int CurieTimer::init(const unsigned int periodHz, void (*userCallBack)()) { - if((periodHz == 0) || (periodHz > MAX_PERIOD)) + if((periodHz == 0) || (periodHz > MAX_PERIOD_HZ)) return -(INVALID_PERIOD); interrupt_disable(timerIrqNum); // Disable Timer at controller diff --git a/libraries/CurieTimerOne/src/CurieTimerOne.h b/libraries/CurieTimerOne/src/CurieTimerOne.h index b8708f0d..b84704bc 100644 --- a/libraries/CurieTimerOne/src/CurieTimerOne.h +++ b/libraries/CurieTimerOne/src/CurieTimerOne.h @@ -48,11 +48,8 @@ // Timer-1 is clocked at ARCV2_TIMER1_CLOCK_FREQ defined in conf.h const unsigned int HZ_USEC = (ARCV2_TIMER1_CLOCK_FREQ / 1000000); // Hz per micro second. -const unsigned int MAX_PERIOD = (0x0FFFFFFFF / HZ_USEC); - -// The two ARC timers. -const unsigned int ARC_TIMER_0 = 0; -const unsigned int ARC_TIMER_1 = 1; +const unsigned int MAX_PERIOD_HZ = 0x0FFFFFFFF; +const unsigned int MAX_PERIOD_USEC = (MAX_PERIOD_HZ / HZ_USEC); // Duty cycle range. const int MAX_DUTY_RANGE = 1023; @@ -80,21 +77,91 @@ typedef enum { // Class: CurieTimer // // Description: -// This class describes the functionalities of a Arc Timer. It has the knowledge -// of only 2 timers available in the h/w - a limitation. The timers are sourced by -// a 32 HHz clock, a constant, used in this class, defined in the conf.h file. +// This class describes the functionalities of a Arc Timer, in particular, timer-1. +// Timer-0 is not available for this module to utilize. The timers are clocked by +// a 32 HHz source and have 32-bit counters. // class CurieTimer { public: - // Constructor. Default is timer-1. - CurieTimer(const unsigned int timerNum = ARC_TIMER_1); + // Constructor. + CurieTimer(); + + // The following methods are similar to the ones found in the AVR TimerOne library. + + //**************************** + // Configuration + //**************************** + + inline void initialize(unsigned long microseconds = 1000000) { + if((microseconds == 0) || (microseconds > MAX_PERIOD_USEC)) + microseconds = 1000000; + periodInUsec = microseconds; + init( (microseconds * HZ_USEC), NULL ); + } + + void setPeriod(unsigned long microseconds); + + //**************************** + // Run Control + //**************************** + + inline void start(void) { + pause(); + pauseCount = 0; + resume(); + } + + inline void stop(void) { return pause(); } + + inline void restart(void) { start(); } + + // Resume the timer from where it was paused. + void resume(void); + + //**************************** + // PWM outputs + //**************************** + + inline void setPwmDuty(char pin, unsigned int duty) { + pwmStart( pin, (int) duty, periodInUsec ); + } + + inline void pwm(char pin, unsigned int duty) { + pwmStart( pin, (int) duty, periodInUsec ); + } + + inline void pwm(char pin, unsigned int duty, unsigned long microseconds) { + pwmStart( pin, (int) duty, microseconds ); + } + + inline void disablePwm(char pin) { + pwmStop(); + } + + //**************************** + // Interrupt Function + //**************************** + + void attachInterrupt(void (*isr)()); + + inline void attachInterrupt(void (*isr)(), unsigned long microseconds) { + attachInterrupt( isr ); + setPeriod( microseconds ); + } + + inline void detachInterrupt(void) { attachInterrupt(NULL); }; + + ///////// + // The following are additional methods provided by Intel for the Curie platform. + //////// // Set up the timer with the input period, in usec, and the call back routine. // Period stays with the timer until it is killed or re/start another round. - inline int start(const unsigned int timerPeriodUsec = 0, + inline int start(const unsigned int timerPeriodUsec, void (*userCallBack)() = NULL) { + periodInUsec = timerPeriodUsec; return( init((timerPeriodUsec * HZ_USEC), userCallBack) ); } // Restarting the timer, start counter from 0. @@ -104,8 +171,6 @@ class CurieTimer void kill(void); // Attach or detach the user call back routine. - void attachInterrupt(void (*userCallBack)()); - void detachInterrupt(void) { return attachInterrupt(NULL); }; // Timer interrupt count. inline unsigned int readTickCount(void) { return tickCnt; } @@ -114,9 +179,6 @@ class CurieTimer // Pausing the timer = no count up, no interrupt. void pause(void); - inline void stop(void) { return pause(); } - // Resume the timer from where it was paused. - void resume(void); // Start software PWM. Note that the timer is consumed once PWM is set. int pwmStart(unsigned int outputPin, double dutyPercentage, unsigned int periodUsec); @@ -148,6 +210,7 @@ class CurieTimer unsigned int pwmPin; unsigned int dutyCycle; unsigned int nonDutyCycle; + unsigned int periodInUsec; void (*isrFuncPtr)(); void (*userCB)(); From 2eb99d10a116a092a2ade78a79d96d164847f9b2 Mon Sep 17 00:00:00 2001 From: agdl Date: Fri, 11 Mar 2016 13:58:24 +0100 Subject: [PATCH 015/222] Removed delay from examples as requested by Tom --- libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino | 3 --- libraries/CurieIMU/examples/Gyro/Gyro.ino | 3 --- 2 files changed, 6 deletions(-) diff --git a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino index 9032795a..89bb0052 100644 --- a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino +++ b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino @@ -56,9 +56,6 @@ void loop() { Serial.print("\t"); Serial.print(az); Serial.println(); - - // wait 5 seconds - delay(5000); } float convertRawAcceleration(int aRaw) { diff --git a/libraries/CurieIMU/examples/Gyro/Gyro.ino b/libraries/CurieIMU/examples/Gyro/Gyro.ino index 426a25b1..81fa30d7 100644 --- a/libraries/CurieIMU/examples/Gyro/Gyro.ino +++ b/libraries/CurieIMU/examples/Gyro/Gyro.ino @@ -56,9 +56,6 @@ void loop() { Serial.print("\t"); Serial.print(gz); Serial.println(); - - // wait 5 seconds - delay(5000); } float convertRawGyro(int gRaw) { From 4fae4ddb4cc9bb14c6c4ccc6147253944c778bb9 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Tue, 8 Mar 2016 15:01:49 -0800 Subject: [PATCH 016/222] CurieI2S initial commit - Minimal functional version --- libraries/CurieI2S/library.properties | 10 + libraries/CurieI2S/src/CurieI2S.cpp | 363 ++++++++++++++++++++++++++ libraries/CurieI2S/src/CurieI2S.h | 136 ++++++++++ variants/arduino_101/variant.h | 5 + 4 files changed, 514 insertions(+) create mode 100644 libraries/CurieI2S/library.properties create mode 100644 libraries/CurieI2S/src/CurieI2S.cpp create mode 100644 libraries/CurieI2S/src/CurieI2S.h diff --git a/libraries/CurieI2S/library.properties b/libraries/CurieI2S/library.properties new file mode 100644 index 00000000..037acaa7 --- /dev/null +++ b/libraries/CurieI2S/library.properties @@ -0,0 +1,10 @@ +name=CurieI2S +version=1.0 +author=Intel +maintainer=Intel +email=dino.tinitigan@intel.com +sentence=Curie I2S Library +paragraph= +url=http://makers.intel.com +architectures=arc32 +core-dependencies=arduino (>=1.6.3) diff --git a/libraries/CurieI2S/src/CurieI2S.cpp b/libraries/CurieI2S/src/CurieI2S.cpp new file mode 100644 index 00000000..86062819 --- /dev/null +++ b/libraries/CurieI2S/src/CurieI2S.cpp @@ -0,0 +1,363 @@ +//CurieI2S.cpp + +#include "CurieI2S.h" +#include + +Curie_I2S CurieI2S; + +static uint32_t _i2s_dma_Rx_Buffer[DMA_BUFFER_SIZE]; +static uint32_t _i2s_dma_Tx_Buffer[DMA_BUFFER_SIZE]; + +static void i2sInterruptHandler(void) +{ + //TODO: Make interrupt handling more atomic + noInterrupts(); + + //tx FIFO full + if(*I2S_STAT & 0x00000400) + { + //Serial.println("tx full"); + + //disable TFIFO_FULL interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFBFFFFFF; + + //start transmit data in FIFO + *I2S_CTRL = *I2S_CTRL | 0x02000000; + delayTicks(3200); + + //clear flags + *I2S_STAT = *I2S_CTRL & 0xFFFFF3FF; + + + //enable TFIFO_EMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x01000000; + + return; + } + + //tx FIFO empty + if(*I2S_STAT & 0x00000100) + { + //Serial.println("tx empty"); + + //disable TFIFO_EMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFEFFFFFF; + + //stop transmission + *I2S_CTRL = *I2S_CTRL & 0xFDFFFFFF; + + //clear flags + *I2S_STAT = *I2S_STAT & 0xFFFFFCFF; + + //enable TFIFO_FULL interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x04000000; + + return; + } + + //tx FIFO almost empty + { + //fill up FIFO from buffer if available; + } + + //overrun and underrun + + interrupts(); +} + +Curie_I2S::Curie_I2S() +{ + +} + +void Curie_I2S::begin(uint32_t sampleRate, uint32_t resolution) +{ + init(); + setSampleRate(sampleRate); + setResolution(resolution); +} +void Curie_I2S::end() +{ + //disable I2S PCLK Clock Gate +} +void Curie_I2S::startRX() +{ + enableRXChannel(1); + syncRX(1); +} + +void Curie_I2S::startTX() +{ + syncTX(1); + delayTicks(800); //add frame delay to prevent sending emptyFrame + muxTX(1); +} + +void Curie_I2S::stopRX() +{ + syncRX(0); + enableRXChannel(0); +} + +void Curie_I2S::stopTX() +{ + //delayTicks(160); + //muxTX(0); + delayTicks(320); + syncTX(0); + //delayTicks(320); + muxTX(0); + //enableTXChannel(0); +} + +void Curie_I2S::setI2SMode(uint32_t mode) +{ + *I2S_DEV_CONF = mode; + uint32_t dev_conf = *I2S_DEV_CONF; + dev_conf &= 0xFFFFF800; + dev_conf |= mode; + *I2S_DEV_CONF = dev_conf; +} + +void Curie_I2S::setSampleRate(uint32_t dividerValue) +{ + uint32_t i2s_srr = *I2S_SRR; + i2s_srr &= I2S_SAMPLERATE_MASK; + i2s_srr |= dividerValue; + *I2S_SRR = i2s_srr; +} + +void Curie_I2S::setResolution(uint32_t resolution) +{ + switch(resolution) + { + case 32: + resolution = I2S_32bit; + break; + case 24: + resolution = I2S_24bit; + break; + case 16: + resolution = I2S_16bit; + break; + default: + break; + } + uint32_t i2s_srr = *I2S_SRR; + i2s_srr &= I2S_RESOLUTION_MASK; + i2s_srr |= resolution; + *I2S_SRR = i2s_srr; +} + +//*************************************************************************************// + +void Curie_I2S::init() +{ + //enable I2S PCLK Clock Gate and I2S Clock + uint32_t clk_gate_ctl = *(uint32_t *)0xB0800018; + clk_gate_ctl |= 0x200200; + *(uint32_t *)0xB0800018 = clk_gate_ctl; + + //configure I2S_CTRL register and set TX as master and RX as slave + uint32_t i2s_ctrl = *I2S_CTRL; + i2s_ctrl &= 0xF9FFFCFC; + i2s_ctrl |= 0x08B00100; + *I2S_CTRL = i2s_ctrl; + + //enable interrupts + //ToDo: Use DMA instead of relying on interrupts + enableInterrupts(); +} + +void Curie_I2S::muxRX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = 1; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(49, mux_mode); //I2S_RXD + SET_PIN_MODE(51, mux_mode); //I2S_RWS + SET_PIN_MODE(50, mux_mode); //I2S_RSCK + g_APinDescription[I2S_RXD].ulPinMode = mux_mode; + g_APinDescription[I2S_RWS].ulPinMode = mux_mode; + g_APinDescription[I2S_RSCK].ulPinMode = mux_mode; +} + +void Curie_I2S::muxTX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = I2S_MUX_MODE; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(g_APinDescription[I2S_TXD].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TWS].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TSCK].ulSocPin, mux_mode); + g_APinDescription[I2S_TXD].ulPinMode = mux_mode; + g_APinDescription[I2S_TWS].ulPinMode = mux_mode; + g_APinDescription[I2S_TSCK].ulPinMode = mux_mode; +} + +void Curie_I2S::initRX() +{ + muxRX(1); + resetRXFIFO(); +} + +void Curie_I2S::initTX() +{ + muxTX(1); + resetTXFIFO(); + enableTXChannel(1); +} + +void Curie_I2S::enableRXChannel(bool enable) +{ + uint32_t i2s_ctrl = *I2S_CTRL; + if(enable) + { + i2s_ctrl |= 0x00000002; + *I2S_CTRL = i2s_ctrl; + } + else + { + i2s_ctrl &= 0xFFFFFFFD; + *I2S_CTRL = i2s_ctrl; + } +} + +void Curie_I2S::enableTXChannel(bool enable) +{ + uint32_t i2s_ctrl = *I2S_CTRL; + if(enable) + { + i2s_ctrl |= 0x00000001; + *I2S_CTRL = i2s_ctrl; + } + else + { + i2s_ctrl &= 0xFFFFFFFE; + *I2S_CTRL = i2s_ctrl; + } +} + +void Curie_I2S::syncTX(bool sync) +{ + uint32_t i2s_ctrl = *I2S_CTRL; + if(sync) + { + i2s_ctrl |= 0x02000000; + *I2S_CTRL = i2s_ctrl; + } + else + { + i2s_ctrl &= 0xFDFFFFFF; + *I2S_CTRL = i2s_ctrl; + } +} + +void Curie_I2S::syncRX(bool sync) +{ + uint32_t i2s_ctrl = *I2S_CTRL; + if(sync) + { + i2s_ctrl |= 0x04000000; + *I2S_CTRL = i2s_ctrl; + } + else + { + i2s_ctrl &= 0xFBFFFFFF; + *I2S_CTRL = i2s_ctrl; + } +} + +void Curie_I2S::resetRXFIFO() +{ + uint32_t i2s_ctrl = *I2S_CTRL; + i2s_ctrl &= 0xFEFFFFFF; +} + +void Curie_I2S::resetTXFIFO() +{ + uint32_t i2s_ctrl = *I2S_CTRL; + i2s_ctrl &= 0xFF7FFFFF; +} + +void Curie_I2S::enableInterrupts() +{ + //Serial.println("enabling interrupts"); + uint32_t int_i2s_mask = *INT_I2S_MASK; + int_i2s_mask &= 0xFFFFFEFF; + *INT_I2S_MASK = int_i2s_mask; + + uint32_t i2s_cid_ctrl = *I2S_CID_CTRL; + i2s_cid_ctrl |= 0x05008000; + *I2S_CID_CTRL = i2s_cid_ctrl; + + interrupt_disable(IRQ_I2S_INTR); + interrupt_connect(IRQ_I2S_INTR , &i2sInterruptHandler); + interrupt_enable(IRQ_I2S_INTR); +} + +void Curie_I2S::transmitFIFO() +{ + if(getTxFIFOLength()) + { + startTX(); + while(getTxFIFOLength()); + stopTX(); + } +} + +void Curie_I2S::transmitFrame() +{ + +} + +void Curie_I2S::pushData(uint32_t data) +{ + if(getTxFIFOLength() < 4) + { + *I2S_DATA_REG = data; + } +} + +void Curie_I2S::fastPushData(uint32_t data) +{ + *I2S_DATA_REG = data; +} + +uint32_t Curie_I2S::pullData() +{ + uint32_t data = *I2S_DATA_REG; + return data; +} + +void Curie_I2S::pushDataFrame(uint32_t leftChData, uint32_t rightChData) +{ + int fifoLength = getTxFIFOLength(); + if(!(fifoLength%2) && (fifoLength < 4)) + { + pushData(leftChData); + pushData(rightChData); + } +} + +uint8_t Curie_I2S::getTxFIFOLength() +{ + uint8_t fifolength = *I2S_TFIFO_STAT & 0x000000FF; + delayTicks(640); + return fifolength; +} + +uint8_t Curie_I2S::getRxFIFOLength() +{ + uint8_t fifolength = *I2S_RFIFO_STAT & 0x000000FF; + delayTicks(640); + return fifolength; +} diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h new file mode 100644 index 00000000..c69b1e5e --- /dev/null +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -0,0 +1,136 @@ +//CurieI2S.h + +#ifndef __CurieI2S_H__ +#define __CurieI2S_H__ + +#include + +//I2S Modes +#define PHILIPS_MODE 0b001000001000 +#define RIGHT_JST_MODE 0b010010010010 +#define LEFT_JST_MODE 0b011010011010 +#define DSP_MODE 0b101000101000 + +//Sample Rate I2S_SRR Values +#define I2S_48K 0x000A000A +#define I2S_44K 0x000F000F +#define I2S_24K 0x001C001C +#define I2S_22K 0x001E001E +#define I2S_12K 0x00530053 +#define I2S_8K 0x007D007D + +//Resolution I2S_SRR Values +#define I2S_32bit 0xF800F800 +#define I2S_24bit 0xB800B800 +#define I2S_16bit 0x78007800 + +//Registers +#define I2S_CTRL (uint32_t *)0xB0003800 //I2S Control Register +#define I2S_STAT (uint32_t *)0xB0003804 //I2S Status Register +#define I2S_SRR (uint32_t *)0xB0003808 //I2S Channels Sample Rate & Resolution Configuration Register +#define I2S_CID_CTRL (uint32_t *)0xB000380C //Clock, Interrupt and DMA Control Register +#define I2S_TFIFO_STAT (uint32_t *)0xB0003810 //Transmit FIFO Status Register +#define I2S_RFIFO_STAT (uint32_t *)0xB0003814 //Receive FIFO Status Register +#define I2S_TFIFO_CTRL (uint32_t *)0xB0003818 //Transmit FIFO Control Register +#define I2S_RFIFO_CTRL (uint32_t *)0xB000381C //Receive FIFO Control Register +#define I2S_DEV_CONF (uint32_t *)0xB0003820 //Device Configuration Register +#define I2S_DATA_REG (uint32_t *)0xB0003850 //Data Register +#define INT_I2S_MASK (uint32_t *)0xB0800468 + +//DMA +//#define DMA_CTL_L0 (uint32_t *))0xB0700000 +#define DMA_BUFFER_SIZE 128 + + +//Masks +#define I2S_SAMPLERATE_MASK 0xF800F800 +#define I2S_RESOLUTION_MASK 0x07FF07FF + + +//I2S Arduino Pins +#define I2S_TXD 7 +#define I2S_TWS 4 +#define I2S_TSCK 2 +#define I2S_RXD 5 +#define I2S_RWS 3 +#define I2S_RSCK 8 + + +class Curie_I2S +{ + private: + uint32_t clock; + bool useDMA; + + void init(); + void muxRX(bool enable); + void muxTX(bool enable); + + void enableRXChannel(bool enable); + void enableTXChannel(bool enable); + + void syncTX(bool sync); + void syncRX(bool sync); + + void resetRXFIFO(); + void resetTXFIFO(); + + void enableInterrupts(); + + public: + Curie_I2S(); + + void begin(uint32_t sampleRate, uint32_t resolution); + + void startRX(); + + void startTX(); + + void stopRX(); + + void stopTX(); + + void setI2SMode(uint32_t mode); + + void setSampleRate(uint32_t dividerValues); + + void setResolution(uint32_t resolution); + + void initRX(); + + void initTX(); + + void end(); + + void transmitFIFO(); + + void transmitFrame(); + + // Pushes a dword into the TX FIFO + void pushData(uint32_t data); + + // Pushes a dword into the TX FIFO without doing any checks + void fastPushData(uint32_t data); + + // Pulls a dword from the rx FIFO + uint32_t pullData(); + + // Pushes a frame (two dwords) into the TX FIFO + void pushDataFrame(uint32_t leftChData, uint32_t rightChData); + + uint8_t getTxFIFOLength(); + + uint8_t getRxFIFOLength(); + + void rsyncLoopback(); + + void tsyncLoopback(); + + inline void i2s_tx_callback(void); + + inline void i2s_rx_callback(void); +}; + +extern Curie_I2S CurieI2S; + +#endif diff --git a/variants/arduino_101/variant.h b/variants/arduino_101/variant.h index 936649af..3b1fa599 100644 --- a/variants/arduino_101/variant.h +++ b/variants/arduino_101/variant.h @@ -78,6 +78,11 @@ extern "C"{ */ #define SPI_MUX_MODE QRK_PMUX_SEL_MODEB +/* + * I2S + */ +#define I2S_MUX_MODE QRK_PMUX_SEL_MODEB + /* * GPIO */ From ccc02128ad2371d3ed35ebb3a01d4146df930e97 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Wed, 23 Mar 2016 18:07:38 -0700 Subject: [PATCH 017/222] CurieI2S use interrupts for Tx -Use interrupts to fill FIFO buffer from TX buffer --- libraries/CurieI2S/src/CurieI2S.cpp | 96 +++++++++++++++++++++++------ libraries/CurieI2S/src/CurieI2S.h | 10 ++- 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/libraries/CurieI2S/src/CurieI2S.cpp b/libraries/CurieI2S/src/CurieI2S.cpp index 86062819..a5800035 100644 --- a/libraries/CurieI2S/src/CurieI2S.cpp +++ b/libraries/CurieI2S/src/CurieI2S.cpp @@ -8,61 +8,113 @@ Curie_I2S CurieI2S; static uint32_t _i2s_dma_Rx_Buffer[DMA_BUFFER_SIZE]; static uint32_t _i2s_dma_Tx_Buffer[DMA_BUFFER_SIZE]; +static struct i2s_ring_buffer _i2s_Rx_Buffer; +static struct i2s_ring_buffer _i2s_Tx_Buffer; + +static struct i2s_ring_buffer *_i2s_Rx_BufferPtr = &_i2s_Rx_Buffer; +static struct i2s_ring_buffer *_i2s_Tx_BufferPtr = &_i2s_Tx_Buffer; + static void i2sInterruptHandler(void) { //TODO: Make interrupt handling more atomic - noInterrupts(); + //noInterrupts(); + //uint32_t fifoL = *I2S_TFIFO_STAT; + + //tx FIFO almost empty + if(*I2S_STAT & 0x00000200) + { + //Serial.println("tx almost empty"); + //Serial.print("I2S_STAT: "); + //Serial.println(*I2S_STAT, HEX); + //Serial.print("I2S_TFIFO_STAT: "); + //Serial.println(fifoL, HEX); + + //disable TFIFO_AEMPTY interrupt + //*I2S_CID_CTRL = *I2S_CID_CTRL & 0xFDFFFFFF; + + //fill FIFO from buffer + if(_i2s_Tx_BufferPtr->head != _i2s_Tx_BufferPtr->tail) + { + int index = _i2s_Tx_BufferPtr->tail; + int cnt = 0; + for(cnt = 0; (index != _i2s_Tx_BufferPtr->head) && (cnt < 2); cnt++) + { + *I2S_DATA_REG = _i2s_Tx_BufferPtr->data[index]; + index = (index+1)%I2S_BUFFER_SIZE; + } + _i2s_Tx_BufferPtr->tail = (_i2s_Tx_BufferPtr->tail + cnt)%I2S_BUFFER_SIZE; + } + //clear flags + *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; + + return; + } + //tx FIFO full if(*I2S_STAT & 0x00000400) { //Serial.println("tx full"); - + //Serial.print("I2S_STAT: "); + //Serial.println(*I2S_STAT, HEX); + //Serial.print("I2S_TFIFO_STAT: "); + //Serial.println(fifoL, HEX); //disable TFIFO_FULL interrupts *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFBFFFFFF; //start transmit data in FIFO *I2S_CTRL = *I2S_CTRL | 0x02000000; - delayTicks(3200); + //delayTicks(3200); //clear flags - *I2S_STAT = *I2S_CTRL & 0xFFFFF3FF; + *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; - //enable TFIFO_EMPTY interrupt - *I2S_CID_CTRL = *I2S_CID_CTRL | 0x01000000; + //enable TFIFO_EMPTY and TFIFO_AEMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x03000000; return; } + //tx FIFO almost full + //if(*I2S_STAT & 0x00000200) + { + //fill up FIFO from buffer if available; + } + //tx FIFO empty if(*I2S_STAT & 0x00000100) { //Serial.println("tx empty"); - + //Serial.print("I2S_STAT: "); + //Serial.println(*I2S_STAT, HEX); + //Serial.print("I2S_TFIFO_STAT: "); + //Serial.println(fifoL, HEX); //disable TFIFO_EMPTY interrupt *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFEFFFFFF; - + + delayTicks(960); //allow enough time to send last frame //stop transmission *I2S_CTRL = *I2S_CTRL & 0xFDFFFFFF; //clear flags - *I2S_STAT = *I2S_STAT & 0xFFFFFCFF; + *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; //enable TFIFO_FULL interrupt *I2S_CID_CTRL = *I2S_CID_CTRL | 0x04000000; + + //Serial.print("CID_CTRL: "); + //Serial.println(*I2S_CID_CTRL, HEX); + return; } - //tx FIFO almost empty - { - //fill up FIFO from buffer if available; - } + //overrun and underrun - interrupts(); + //interrupts(); } Curie_I2S::Curie_I2S() @@ -164,6 +216,10 @@ void Curie_I2S::init() i2s_ctrl |= 0x08B00100; *I2S_CTRL = i2s_ctrl; + //set threshold for FIFOs + *I2S_TFIFO_CTRL |= 0x00030002; + *I2S_RFIFO_CTRL |= 0x00030002; + //enable interrupts //ToDo: Use DMA instead of relying on interrupts enableInterrupts(); @@ -296,7 +352,7 @@ void Curie_I2S::enableInterrupts() *INT_I2S_MASK = int_i2s_mask; uint32_t i2s_cid_ctrl = *I2S_CID_CTRL; - i2s_cid_ctrl |= 0x05008000; + i2s_cid_ctrl |= 0x0F008000; *I2S_CID_CTRL = i2s_cid_ctrl; interrupt_disable(IRQ_I2S_INTR); @@ -321,9 +377,11 @@ void Curie_I2S::transmitFrame() void Curie_I2S::pushData(uint32_t data) { - if(getTxFIFOLength() < 4) + int i = (uint32_t)(_i2s_Tx_BufferPtr->head +1) % I2S_BUFFER_SIZE; + if(i != _i2s_Tx_BufferPtr->tail) { - *I2S_DATA_REG = data; + _i2s_Tx_BufferPtr->data[_i2s_Tx_BufferPtr->head] = data; + _i2s_Tx_BufferPtr->head = i; } } @@ -340,8 +398,8 @@ uint32_t Curie_I2S::pullData() void Curie_I2S::pushDataFrame(uint32_t leftChData, uint32_t rightChData) { - int fifoLength = getTxFIFOLength(); - if(!(fifoLength%2) && (fifoLength < 4)) + //int fifoLength = getTxFIFOLength(); + //if(!(fifoLength%2) && (fifoLength < 4)) { pushData(leftChData); pushData(rightChData); diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h index c69b1e5e..8e402bdb 100644 --- a/libraries/CurieI2S/src/CurieI2S.h +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -55,6 +55,14 @@ #define I2S_RWS 3 #define I2S_RSCK 8 +#define I2S_BUFFER_SIZE 256 + +struct i2s_ring_buffer +{ + uint32_t data[I2S_BUFFER_SIZE]; + int head = 0; + int tail = 0; +}; class Curie_I2S { @@ -106,7 +114,7 @@ class Curie_I2S void transmitFrame(); - // Pushes a dword into the TX FIFO + // Pushes a dword into the TX buffer void pushData(uint32_t data); // Pushes a dword into the TX FIFO without doing any checks From a54f5132630fb2825e27d84cf4ddf3d8ee22192a Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Thu, 31 Mar 2016 11:50:12 -0700 Subject: [PATCH 018/222] Jira-575, Jira-506: Bug fixes to print float and double correctly, in a string or std output. --- cores/arduino/Print.cpp | 29 +++++++++--- cores/arduino/WString.cpp | 8 ++-- cores/arduino/stdlib_noniso.cpp | 79 ++++++++++++++++++++++++++++++--- cores/arduino/stdlib_noniso.h | 4 +- 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index aa8c9404..2e5a5352 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -289,18 +289,29 @@ size_t Print::printLongLong(unsigned long long n, uint8_t base) { size_t Print::printFloat(double number, uint8_t digits) { size_t n = 0; + int exponent = 0; + double tmp; if (isnan(number)) return print("nan"); if (isinf(number)) return print("inf"); - if (number > 4294967040.0) return print ("ovf"); // constant determined empirically - if (number <-4294967040.0) return print ("ovf"); // constant determined empirically // Handle negative numbers - if (number < 0.0) - { - n += print('-'); - number = -number; + if (number < 0.0) { + n += print('-'); + number = -number; + } + + // Chk if integer part has more than 8 digits. + tmp = number; + while (true) { + tmp /= 10.0; + exponent++; + if (tmp < 10.0) break; } + if (exponent > 8) + number = tmp; + else + exponent = 0; // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; @@ -328,5 +339,11 @@ size_t Print::printFloat(double number, uint8_t digits) remainder -= toPrint; } + // Print the exponent portion + if (exponent) { + n += print("e+"); + n += print(exponent); + } + return n; } diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 2f748fb8..ec03d1ae 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -135,14 +135,14 @@ String::String(float value, unsigned char decimalPlaces) { init(); char buf[33]; - *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + *this = dtostrf(value, (33 - 1), decimalPlaces, buf); } String::String(double value, unsigned char decimalPlaces) { init(); char buf[33]; - *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + *this = dtostrf(value, (33 - 1), decimalPlaces, buf); } String::~String() @@ -363,14 +363,14 @@ unsigned char String::concat(unsigned long long num) unsigned char String::concat(float num) { char buf[20]; - char* string = dtostrf(num, 4, 2, buf); + char* string = dtostrf(num, (20 - 1), 2, buf); return concat(string, strlen(string)); } unsigned char String::concat(double num) { char buf[20]; - char* string = dtostrf(num, 4, 2, buf); + char* string = dtostrf(num, (20 - 1), 2, buf); return concat(string, strlen(string)); } diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 874dfec4..89f4f1d5 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -147,9 +147,76 @@ char* ultoa( unsigned long val, char *string, int radix ) return string; } -char *dtostrf (double val, signed char width, unsigned char prec, char *sout) { - char fmt[20]; - sprintf(fmt, "%%%d.%df", width, prec); - sprintf(sout, fmt, val); - return sout; -} \ No newline at end of file +char * dtostrf(double number, unsigned char width, unsigned char prec, char *s) { + + if (isnan(number)) { + strcpy(s, "nan"); + return s; + } + if (isinf(number)) { + strcpy(s, "inf"); + return s; + } + + char* out = s; + int exponent = 0; + unsigned char len, expLen; + double tmp; + + // Handle negative numbers + if (number < 0.0) { + *out++ = '-'; + number = -number; + } + + // The integer portion has to be <= 8 digits. Otherwise, the + // string is in exponent format. + tmp = number; + for (;;) { + tmp /= 10.0; + exponent++; + if (tmp < 10.0) break; + } + if (exponent > 8) + number = tmp; + else + exponent = 0; + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i = 0; i < prec; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + out += sprintf(out, "%ld", int_part); + + // Don't go beyond the given width of the string + len = (unsigned char)(out - s); + expLen = (exponent == 0) ? 0 : 5; // 5 places for exponent expression + if ((prec + len + expLen) > width) + prec = width - len - expLen; + + // Print the decimal point, but only if there are digits beyond + if (prec > 0) { + *out = '.'; + ++out; + prec--; + // Copy character by character to 'out' string + for (unsigned char decShift = prec; decShift > 0; decShift--) { + remainder *= 10.0; + sprintf(out, "%d", (int)remainder); + out++; + remainder -= (double)(int)remainder; + } + } + + // Print the exponent if exists + if (exponent) + sprintf(out, "e+%.3d", exponent); + + return s; +} diff --git a/cores/arduino/stdlib_noniso.h b/cores/arduino/stdlib_noniso.h index fc48a535..1d0d8d06 100644 --- a/cores/arduino/stdlib_noniso.h +++ b/cores/arduino/stdlib_noniso.h @@ -37,10 +37,10 @@ char* utoa (unsigned int val, char *s, int radix); char* ultoa (unsigned long val, char *s, int radix); -char* dtostrf (double val, signed char width, unsigned char prec, char *s); +char* dtostrf (double val, unsigned char width, unsigned char prec, char *s); #ifdef __cplusplus } // extern "C" #endif -#endif \ No newline at end of file +#endif From 2bca6fc912b51200ad12b833e52321e65ccf553b Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Wed, 30 Mar 2016 12:18:36 -0700 Subject: [PATCH 019/222] Interrupt based I2S library -CurieI2S using interrupts --- libraries/CurieI2S/keywords.txt | 48 +++ libraries/CurieI2S/library.properties | 3 +- libraries/CurieI2S/src/CurieI2S.cpp | 440 ++++++++++++++++++++------ libraries/CurieI2S/src/CurieI2S.h | 134 ++++++-- 4 files changed, 491 insertions(+), 134 deletions(-) create mode 100644 libraries/CurieI2S/keywords.txt diff --git a/libraries/CurieI2S/keywords.txt b/libraries/CurieI2S/keywords.txt new file mode 100644 index 00000000..203a819c --- /dev/null +++ b/libraries/CurieI2S/keywords.txt @@ -0,0 +1,48 @@ +####################################### +# Syntax Coloring Map For CurieI2S +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Curie_I2S KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +start KEYWORD2 +stop KEYWORD2 +begin KEYWORD2 +enableRX KEYWORD2 +enableTX KEYWORD2 +startRX KEYWORD2 +startTX KEYWORD2 +stopRX KEYWORD2 +stopTX KEYWORD2 +setI2SMode KEYWORD2 +setResolution KEYWORD2 +initRX KEYWORD2 +initTX KEYWORD2 +end KEYWORD2 +pushData KEYWORD2 +fastPushData KEYWORD2 +write KEYWORD2 +pullData KEYWORD2 +read KEYWORD2 +requestdword KEYWORD2 +available KEYWORD2 +availableTx KEYWORD2 +attachRxInterrupt KEYWORD2 +detachRxInterrupt KEYWORD2 +attachTxInterrupt KEYWORD2 +detachTxInterrupt KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### +CurieI2S KEYWORD2 +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/CurieI2S/library.properties b/libraries/CurieI2S/library.properties index 037acaa7..2e0516cd 100644 --- a/libraries/CurieI2S/library.properties +++ b/libraries/CurieI2S/library.properties @@ -3,8 +3,9 @@ version=1.0 author=Intel maintainer=Intel email=dino.tinitigan@intel.com -sentence=Curie I2S Library +sentence=Curie I2S Library for Arduino/Genuino 101 paragraph= +category=Communication url=http://makers.intel.com architectures=arc32 core-dependencies=arduino (>=1.6.3) diff --git a/libraries/CurieI2S/src/CurieI2S.cpp b/libraries/CurieI2S/src/CurieI2S.cpp index a5800035..8eedbecd 100644 --- a/libraries/CurieI2S/src/CurieI2S.cpp +++ b/libraries/CurieI2S/src/CurieI2S.cpp @@ -1,3 +1,23 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 +// +//*************************************************************** + //CurieI2S.cpp #include "CurieI2S.h" @@ -5,8 +25,8 @@ Curie_I2S CurieI2S; -static uint32_t _i2s_dma_Rx_Buffer[DMA_BUFFER_SIZE]; -static uint32_t _i2s_dma_Tx_Buffer[DMA_BUFFER_SIZE]; +//static uint32_t _i2s_dma_Rx_Buffer[DMA_BUFFER_SIZE]; +//static uint32_t _i2s_dma_Tx_Buffer[DMA_BUFFER_SIZE]; static struct i2s_ring_buffer _i2s_Rx_Buffer; static struct i2s_ring_buffer _i2s_Tx_Buffer; @@ -14,61 +34,140 @@ static struct i2s_ring_buffer _i2s_Tx_Buffer; static struct i2s_ring_buffer *_i2s_Rx_BufferPtr = &_i2s_Rx_Buffer; static struct i2s_ring_buffer *_i2s_Tx_BufferPtr = &_i2s_Tx_Buffer; +//static int _i2s_frame_delay = 960; + static void i2sInterruptHandler(void) { - //TODO: Make interrupt handling more atomic - //noInterrupts(); - //uint32_t fifoL = *I2S_TFIFO_STAT; + //Serial.println("i2s int"); + uint32_t i2s_stat = *I2S_STAT; + + //RX FIFO almost full + if((*I2S_STAT & 0x00008000) && (*I2S_CID_CTRL & 0x80000000)) + { + //Serial.println("rx almost full"); + + //disable RFIFO_AFULL interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL & 0x7FFFFFFF; + + int index; + int fifoDataLength = (*I2S_RFIFO_STAT & 0x0000000F); + + for(int i = 0; i < fifoDataLength; i++) + { + index = (uint32_t)(_i2s_Rx_BufferPtr->head +1) % I2S_BUFFER_SIZE; + uint32_t data = *I2S_DATA_REG; + if(index != _i2s_Rx_BufferPtr->tail) + { + _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->head] = data; + _i2s_Rx_BufferPtr->head = index; + } + #ifdef I2S_DEBUG + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, LOW); + #endif + + } + + //enable RFIFO_EMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x10000000; + + //clear flags + i2s_stat = i2s_stat & 0xFFFF0FFF; + *I2S_STAT = i2s_stat | 0x00000010; + + //call rx callback + CurieI2S.i2s_rx_callback(); + + return; + } + + //RX FIFO empty + if((*I2S_STAT & 0x00001000) && (*I2S_CID_CTRL & 0x10000000)) + { + //Serial.println("rx empty"); + + //disable RFIFO_EMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xEFFFFFFF; + + #ifdef I2S_DEBUG + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, LOW); + #endif + + //enable RFIFO_AFULL interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x80000000; + + //clear flags + //*I2S_STAT = *I2S_STAT & 0xFFFFEFFF; + i2s_stat = i2s_stat & 0xFFFF0FFF; + *I2S_STAT = i2s_stat | 0x00000010; + + return; + } - //tx FIFO almost empty - if(*I2S_STAT & 0x00000200) + //TX FIFO almost empty + if((*I2S_STAT & 0x00000200) && (*I2S_CID_CTRL & 0x02000000)) { //Serial.println("tx almost empty"); - //Serial.print("I2S_STAT: "); - //Serial.println(*I2S_STAT, HEX); - //Serial.print("I2S_TFIFO_STAT: "); - //Serial.println(fifoL, HEX); - //disable TFIFO_AEMPTY interrupt - //*I2S_CID_CTRL = *I2S_CID_CTRL & 0xFDFFFFFF; + //disable TFIFO_AEMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFDFFFFFF; + + #ifdef I2S_DEBUG + //digitalWrite(I2S_DEBUG_PIN, HIGH); + //digitalWrite(I2S_DEBUG_PIN, LOW); + //digitalWrite(I2S_DEBUG_PIN, HIGH); + //digitalWrite(I2S_DEBUG_PIN, LOW); + //digitalWrite(I2S_DEBUG_PIN, HIGH); + //digitalWrite(I2S_DEBUG_PIN, LOW); + #endif - //fill FIFO from buffer if(_i2s_Tx_BufferPtr->head != _i2s_Tx_BufferPtr->tail) { int index = _i2s_Tx_BufferPtr->tail; int cnt = 0; - for(cnt = 0; (index != _i2s_Tx_BufferPtr->head) && (cnt < 2); cnt++) + int fifoSpace = (4 - (*I2S_TFIFO_STAT & 0x0000000F)); + for(cnt = 0; (index != (_i2s_Tx_BufferPtr->head)) && (cnt < fifoSpace); cnt++) { *I2S_DATA_REG = _i2s_Tx_BufferPtr->data[index]; index = (index+1)%I2S_BUFFER_SIZE; } _i2s_Tx_BufferPtr->tail = (_i2s_Tx_BufferPtr->tail + cnt)%I2S_BUFFER_SIZE; } - - //clear flags - *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; + else + { + //Serial.println("buff empty"); + } + //clear TX flags + i2s_stat = i2s_stat & 0xFFFFFCFF; + *I2S_STAT = i2s_stat | 0x00000001; + + //enable TFIFO_EMPTY and TFIFO_AEMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x03000000; return; } - //tx FIFO full - if(*I2S_STAT & 0x00000400) + + //TX FIFO full + if((*I2S_STAT & 0x00000400) && (*I2S_CID_CTRL & 0x04000000)) { - //Serial.println("tx full"); - //Serial.print("I2S_STAT: "); - //Serial.println(*I2S_STAT, HEX); - //Serial.print("I2S_TFIFO_STAT: "); - //Serial.println(fifoL, HEX); + #ifdef I2S_DEBUG + //digitalWrite(I2S_DEBUG_PIN, HIGH); + //digitalWrite(I2S_DEBUG_PIN, LOW); + #endif + //disable TFIFO_FULL interrupts *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFBFFFFFF; //start transmit data in FIFO - *I2S_CTRL = *I2S_CTRL | 0x02000000; - //delayTicks(3200); - - //clear flags - *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; + //*I2S_CTRL = *I2S_CTRL | 0x02000000; + //clear TX flags + i2s_stat = i2s_stat & 0xFFFFFBFF; + *I2S_STAT = i2s_stat | 0x00000001; //enable TFIFO_EMPTY and TFIFO_AEMPTY interrupt *I2S_CID_CTRL = *I2S_CID_CTRL | 0x03000000; @@ -76,50 +175,96 @@ static void i2sInterruptHandler(void) return; } - //tx FIFO almost full - //if(*I2S_STAT & 0x00000200) + //TX FIFO almost full + /** + if((*I2S_STAT & 0x00000200) && (*I2S_CID_CTRL & 0x02000000)) { - //fill up FIFO from buffer if available; } + **/ - //tx FIFO empty - if(*I2S_STAT & 0x00000100) + //TX FIFO empty + if((*I2S_STAT & 0x00000100) && (*I2S_CID_CTRL & 0x01000000)) { - //Serial.println("tx empty"); - //Serial.print("I2S_STAT: "); - //Serial.println(*I2S_STAT, HEX); - //Serial.print("I2S_TFIFO_STAT: "); - //Serial.println(fifoL, HEX); - //disable TFIFO_EMPTY interrupt - *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFEFFFFFF; - - delayTicks(960); //allow enough time to send last frame - //stop transmission - *I2S_CTRL = *I2S_CTRL & 0xFDFFFFFF; - - //clear flags - *I2S_STAT = *I2S_CTRL & 0xFFFFF0FF; - - //enable TFIFO_FULL interrupt - *I2S_CID_CTRL = *I2S_CID_CTRL | 0x04000000; - - - //Serial.print("CID_CTRL: "); - //Serial.println(*I2S_CID_CTRL, HEX); + //Serial.println("tx fifo empty"); + int fifoLength = *I2S_TFIFO_STAT & 0x0000000F; + if(!fifoLength) + { + //disable TFIFO_EMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFEFFFFFF; + #ifdef I2S_DEBUG + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, LOW); + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, LOW); + #endif + + //make sure buffer there is no more data in buffer to put into fifo + if(_i2s_Tx_BufferPtr->head != _i2s_Tx_BufferPtr->tail) + { + int index = _i2s_Tx_BufferPtr->tail; + int cnt = 0; + for(cnt = 0; (index != (_i2s_Tx_BufferPtr->head)) && (cnt < 4); cnt++) + { + *I2S_DATA_REG = _i2s_Tx_BufferPtr->data[index]; + index = (index+1)%I2S_BUFFER_SIZE; + } + _i2s_Tx_BufferPtr->tail = (_i2s_Tx_BufferPtr->tail + cnt)%I2S_BUFFER_SIZE; + + //enable Tx interrrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x07000000; + } + else + { + //TXFIFO and tx buffer empty + + //last frame delay + delayTicks(960); + //stop transmission + *I2S_CTRL = *I2S_CTRL & 0xFDFFFFFE; + + //clear flags + i2s_stat = i2s_stat & 0xFFFFF0FF; + *I2S_STAT = i2s_stat | 0x00000001; + + //call rx callback + CurieI2S.i2s_tx_callback(); + + //enable TFIFO_AEMPTY and TFIFO_FULL interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x06000000; + + return; + } + } + else + { + //not really empty + //clear flags + i2s_stat = i2s_stat & 0xFFFFFEFF; + *I2S_STAT = i2s_stat | 0x00000001; + + //enable TFIFO_EMPTY and TFIFO_AEMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x03000000; + } return; } + /** + Serial.println("unk int"); + Serial.print("I2S_STAT: "); + Serial.println(*I2S_STAT, HEX); + Serial.print("CID_CTRL: "); + Serial.println(*I2S_CID_CTRL, HEX); + **/ + //TODO: handle overrun and underrun - //overrun and underrun - - //interrupts(); } Curie_I2S::Curie_I2S() { - + i2s_txCB = NULL; + i2s_rxCB = NULL; } void Curie_I2S::begin(uint32_t sampleRate, uint32_t resolution) @@ -131,7 +276,27 @@ void Curie_I2S::begin(uint32_t sampleRate, uint32_t resolution) void Curie_I2S::end() { //disable I2S PCLK Clock Gate + *CLK_GATE_CTL = *CLK_GATE_CTL & 0xFFDFFDFF; + muxRX(0); + enableRXChannel(0); + syncRX(0); + muxTX(0); + enableTXChannel(0); + syncTX(0); } + +void Curie_I2S::enableTX() +{ + enableTXChannel(1); + syncTX(1); +} + +void Curie_I2S::enableRX() +{ + enableRXChannel(1); + syncRX(1); +} + void Curie_I2S::startRX() { enableRXChannel(1); @@ -140,9 +305,26 @@ void Curie_I2S::startRX() void Curie_I2S::startTX() { - syncTX(1); - delayTicks(800); //add frame delay to prevent sending emptyFrame - muxTX(1); + //make sure fifo is empty + #ifdef I2S_DEBUG + digitalWrite(I2S_DEBUG_PIN, HIGH); + digitalWrite(I2S_DEBUG_PIN, LOW); + #endif + resetTXFIFO(); + int cnt = 0; + if(_i2s_Tx_BufferPtr->head != _i2s_Tx_BufferPtr->tail) + { + int index = _i2s_Tx_BufferPtr->tail; + for(cnt = 0; (index != _i2s_Tx_BufferPtr->head) && (cnt < 4); cnt++) + { + *I2S_DATA_REG = _i2s_Tx_BufferPtr->data[index]; + index = (index+1)%I2S_BUFFER_SIZE; + } + _i2s_Tx_BufferPtr->tail = (_i2s_Tx_BufferPtr->tail + cnt)%I2S_BUFFER_SIZE; + enableTX(); + //enable TFIFO_EMPTY and TFIFO_AEMPTY interrupt + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x02000000; + } } void Curie_I2S::stopRX() @@ -153,13 +335,7 @@ void Curie_I2S::stopRX() void Curie_I2S::stopTX() { - //delayTicks(160); - //muxTX(0); - delayTicks(320); syncTX(0); - //delayTicks(320); - muxTX(0); - //enableTXChannel(0); } void Curie_I2S::setI2SMode(uint32_t mode) @@ -204,21 +380,19 @@ void Curie_I2S::setResolution(uint32_t resolution) //*************************************************************************************// void Curie_I2S::init() -{ +{ //enable I2S PCLK Clock Gate and I2S Clock - uint32_t clk_gate_ctl = *(uint32_t *)0xB0800018; - clk_gate_ctl |= 0x200200; - *(uint32_t *)0xB0800018 = clk_gate_ctl; + *CLK_GATE_CTL = *CLK_GATE_CTL | 0x00200200; //configure I2S_CTRL register and set TX as master and RX as slave uint32_t i2s_ctrl = *I2S_CTRL; - i2s_ctrl &= 0xF9FFFCFC; - i2s_ctrl |= 0x08B00100; + i2s_ctrl &= 0xE0FFFCFC; + i2s_ctrl |= 0x00B00100; *I2S_CTRL = i2s_ctrl; //set threshold for FIFOs - *I2S_TFIFO_CTRL |= 0x00030002; - *I2S_RFIFO_CTRL |= 0x00030002; + *I2S_TFIFO_CTRL |= 0x00030003; + *I2S_RFIFO_CTRL |= 0x00010002; //enable interrupts //ToDo: Use DMA instead of relying on interrupts @@ -230,7 +404,7 @@ void Curie_I2S::muxRX(bool enable) int mux_mode = GPIO_MUX_MODE; if(enable) { - mux_mode = 1; + mux_mode = I2S_MUX_MODE; } /* Set SoC pin mux configuration */ @@ -263,13 +437,18 @@ void Curie_I2S::initRX() { muxRX(1); resetRXFIFO(); + //enableRXChannel(1); + //enable RX interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x80000000; } void Curie_I2S::initTX() { muxTX(1); resetTXFIFO(); - enableTXChannel(1); + //enableTXChannel(1); + //enable TX interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x06000000; } void Curie_I2S::enableRXChannel(bool enable) @@ -346,13 +525,13 @@ void Curie_I2S::resetTXFIFO() void Curie_I2S::enableInterrupts() { - //Serial.println("enabling interrupts"); - uint32_t int_i2s_mask = *INT_I2S_MASK; + uint32_t int_i2s_mask = *I2S_MASK_INT; int_i2s_mask &= 0xFFFFFEFF; - *INT_I2S_MASK = int_i2s_mask; + *I2S_MASK_INT = int_i2s_mask; uint32_t i2s_cid_ctrl = *I2S_CID_CTRL; - i2s_cid_ctrl |= 0x0F008000; + //i2s_cid_ctrl |= 0x87008000; + i2s_cid_ctrl |= 0x00008000; *I2S_CID_CTRL = i2s_cid_ctrl; interrupt_disable(IRQ_I2S_INTR); @@ -360,28 +539,25 @@ void Curie_I2S::enableInterrupts() interrupt_enable(IRQ_I2S_INTR); } -void Curie_I2S::transmitFIFO() -{ - if(getTxFIFOLength()) - { - startTX(); - while(getTxFIFOLength()); - stopTX(); - } -} - -void Curie_I2S::transmitFrame() +int Curie_I2S::pushData(uint32_t data) { - -} + //disable TFIFO_AEMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL & 0xFDFFFFFF; -void Curie_I2S::pushData(uint32_t data) -{ int i = (uint32_t)(_i2s_Tx_BufferPtr->head +1) % I2S_BUFFER_SIZE; if(i != _i2s_Tx_BufferPtr->tail) { _i2s_Tx_BufferPtr->data[_i2s_Tx_BufferPtr->head] = data; _i2s_Tx_BufferPtr->head = i; + //enable TFIFO_AEMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x02000000; + return 1; + } + else + { + //enable TFIFO_AEMPTY interrupts + *I2S_CID_CTRL = *I2S_CID_CTRL | 0x02000000; + return 0; } } @@ -396,26 +572,80 @@ uint32_t Curie_I2S::pullData() return data; } -void Curie_I2S::pushDataFrame(uint32_t leftChData, uint32_t rightChData) +uint32_t Curie_I2S::requestdword() { - //int fifoLength = getTxFIFOLength(); - //if(!(fifoLength%2) && (fifoLength < 4)) + if(_i2s_Rx_BufferPtr->head != _i2s_Rx_BufferPtr->tail) + { + uint32_t data = _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->tail]; + _i2s_Rx_BufferPtr->tail = (_i2s_Rx_BufferPtr->tail + 1)%I2S_BUFFER_SIZE; + return data; + } + else { - pushData(leftChData); - pushData(rightChData); + //check if there is data in the FIFO + if(*I2S_RFIFO_STAT & 0x0000000F) + { + int index = (uint32_t)(_i2s_Rx_BufferPtr->head +1) % I2S_BUFFER_SIZE; + uint32_t data = *I2S_DATA_REG; + if(index != _i2s_Rx_BufferPtr->tail) + { + _i2s_Rx_BufferPtr->data[_i2s_Rx_BufferPtr->head] = data; + _i2s_Rx_BufferPtr->head = index; + } + _i2s_Rx_BufferPtr->tail = (_i2s_Rx_BufferPtr->tail + 1)%I2S_BUFFER_SIZE; + return data; + } + } + return 0; +} + +uint16_t Curie_I2S::available() +{ + return (uint16_t)(_i2s_Rx_BufferPtr->head - _i2s_Rx_BufferPtr->tail)%I2S_BUFFER_SIZE; +} + +uint16_t Curie_I2S::availableTx() +{ + if(_i2s_Tx_BufferPtr->tail == _i2s_Tx_BufferPtr->head) + { + return I2S_BUFFER_SIZE; + } + else + { + return ((_i2s_Tx_BufferPtr->tail+I2S_BUFFER_SIZE) - _i2s_Tx_BufferPtr->head+1)%I2S_BUFFER_SIZE; } } uint8_t Curie_I2S::getTxFIFOLength() { uint8_t fifolength = *I2S_TFIFO_STAT & 0x000000FF; - delayTicks(640); return fifolength; } uint8_t Curie_I2S::getRxFIFOLength() { uint8_t fifolength = *I2S_RFIFO_STAT & 0x000000FF; - delayTicks(640); return fifolength; } + +void Curie_I2S::attachRxInterrupt(void (*userCallBack)()) +{ + i2s_rxCB = userCallBack; +} + +void Curie_I2S::attachTxInterrupt(void (*userCallBack)()) +{ + i2s_txCB = userCallBack; +} + +inline void Curie_I2S::i2s_rx_callback(void) +{ + if(i2s_rxCB != NULL) + i2s_rxCB(); +} + +inline void Curie_I2S::i2s_tx_callback(void) +{ + if(i2s_txCB != NULL) + i2s_txCB(); +} diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h index 8e402bdb..c7d1345f 100644 --- a/libraries/CurieI2S/src/CurieI2S.h +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -1,3 +1,23 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 +// +//*************************************************************** + //CurieI2S.h #ifndef __CurieI2S_H__ @@ -25,21 +45,22 @@ #define I2S_16bit 0x78007800 //Registers -#define I2S_CTRL (uint32_t *)0xB0003800 //I2S Control Register -#define I2S_STAT (uint32_t *)0xB0003804 //I2S Status Register -#define I2S_SRR (uint32_t *)0xB0003808 //I2S Channels Sample Rate & Resolution Configuration Register -#define I2S_CID_CTRL (uint32_t *)0xB000380C //Clock, Interrupt and DMA Control Register -#define I2S_TFIFO_STAT (uint32_t *)0xB0003810 //Transmit FIFO Status Register -#define I2S_RFIFO_STAT (uint32_t *)0xB0003814 //Receive FIFO Status Register -#define I2S_TFIFO_CTRL (uint32_t *)0xB0003818 //Transmit FIFO Control Register -#define I2S_RFIFO_CTRL (uint32_t *)0xB000381C //Receive FIFO Control Register -#define I2S_DEV_CONF (uint32_t *)0xB0003820 //Device Configuration Register -#define I2S_DATA_REG (uint32_t *)0xB0003850 //Data Register -#define INT_I2S_MASK (uint32_t *)0xB0800468 +#define I2S_CTRL (uint32_t *)0xB0003800 //I2S Control Register +#define I2S_STAT (volatile uint32_t *)0xB0003804 //I2S Status Register +#define I2S_SRR (uint32_t *)0xB0003808 //I2S Channels Sample Rate & Resolution Configuration Register +#define I2S_CID_CTRL (uint32_t *)0xB000380C //Clock, Interrupt and DMA Control Register +#define I2S_TFIFO_STAT (volatile uint32_t *)0xB0003810 //Transmit FIFO Status Register +#define I2S_RFIFO_STAT (volatile uint32_t *)0xB0003814 //Receive FIFO Status Register +#define I2S_TFIFO_CTRL (uint32_t *)0xB0003818 //Transmit FIFO Control Register +#define I2S_RFIFO_CTRL (uint32_t *)0xB000381C //Receive FIFO Control Register +#define I2S_DEV_CONF (uint32_t *)0xB0003820 //Device Configuration Register +#define I2S_DATA_REG (volatile uint32_t *)0xB0003850 //Data Register +#define I2S_MASK_INT (uint32_t *)0xB0800468 //Host Processor Interrupt Routing Mask 7 +#define CLK_GATE_CTL (uint32_t *)0xB0800018 //CLK_GATE_CTL register //DMA //#define DMA_CTL_L0 (uint32_t *))0xB0700000 -#define DMA_BUFFER_SIZE 128 +//#define DMA_BUFFER_SIZE 128 //Masks @@ -57,11 +78,18 @@ #define I2S_BUFFER_SIZE 256 +//#define I2S_DEBUG + +#ifdef I2S_DEBUG +#define I2S_DEBUG_PIN 12 +#endif + struct i2s_ring_buffer { - uint32_t data[I2S_BUFFER_SIZE]; - int head = 0; - int tail = 0; + volatile uint32_t data[I2S_BUFFER_SIZE]; + volatile int head = 0; + volatile int tail= 0; + volatile bool lock = false; }; class Curie_I2S @@ -70,73 +98,123 @@ class Curie_I2S uint32_t clock; bool useDMA; + // initializes i2s interface void init(); + + // mux/demux the i2s rx pins into i2s mode void muxRX(bool enable); + + // mux/demux the i2s tx pins into i2s mode void muxTX(bool enable); + // enables/disables the i2s rx channel void enableRXChannel(bool enable); + + // enables/disables the i2s tx channel void enableTXChannel(bool enable); + // rx sync unit void syncTX(bool sync); + + // tx sync unit void syncRX(bool sync); + // resets RX FIFO pointer void resetRXFIFO(); + + // resets TX FIFO pointer void resetTXFIFO(); + //enables i2s interrupts void enableInterrupts(); + void (*i2s_txCB)(); + + void (*i2s_rxCB)(); + public: Curie_I2S(); + // void begin(uint32_t sampleRate, uint32_t resolution); + // enables rx channel + void enableRX(); + + // enables tx channel + void enableTX(); + + // starts listening to the rx channel void startRX(); + // starts transmission of data to the tx channel void startTX(); + // stops listening on rx channel void stopRX(); + // stops transmission on tx channel void stopTX(); + // sets the mode of operation for the i2s interface void setI2SMode(uint32_t mode); + // sets sample rate bor both i2s channels void setSampleRate(uint32_t dividerValues); + // sets the bit resolution for both i2s cahnnels void setResolution(uint32_t resolution); + // Initializes the i2s rx channel void initRX(); + // Initializes the i2s tx channel void initTX(); void end(); - void transmitFIFO(); - - void transmitFrame(); - // Pushes a dword into the TX buffer - void pushData(uint32_t data); + int pushData(uint32_t data); - // Pushes a dword into the TX FIFO without doing any checks + // Pushes a dword into the TX FIFO void fastPushData(uint32_t data); - // Pulls a dword from the rx FIFO + void write(); + + // Pulls a dword directly from the RX FIFO uint32_t pullData(); - // Pushes a frame (two dwords) into the TX FIFO - void pushDataFrame(uint32_t leftChData, uint32_t rightChData); + // Pulls a dword from the tail of the rx buffer + uint32_t read() {return requestdword(); }; + + // Pulls a dword from the tail of the rx buffer + uint32_t requestdword(); + + // Returns number of dword avaialable in the rx buffer + uint16_t available(); + + // Returns the number of space available in the tx buffer; + uint16_t availableTx(); uint8_t getTxFIFOLength(); uint8_t getRxFIFOLength(); - void rsyncLoopback(); + // Attach user callback when there is data pushed into the rx buffer from the RX_FIFO + void attachRxInterrupt(void (*userCallBack)()); + + void detachRxInterrupt(void) { return attachTxInterrupt(NULL); }; + + // Attach user callback when that gets called when TX_FIFO is empty(transmission done); + void attachTxInterrupt(void (*userCallBack)()); - void tsyncLoopback(); + void detachTxInterrupt(void) { return attachRxInterrupt(NULL); }; - inline void i2s_tx_callback(void); + //tx callback + void i2s_tx_callback(void); - inline void i2s_rx_callback(void); + //rx callback + void i2s_rx_callback(void); }; extern Curie_I2S CurieI2S; From 89dd2287dfd41a12db0a34eed7d94b8593b2e5da Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Fri, 1 Apr 2016 12:06:36 -0700 Subject: [PATCH 020/222] CurieI2S add examples -add basic examples using callback functions/interrupts -add callback function to fill tx buffer --- .../I2S_RxCallback/I2S_RxCallback.ino | 53 ++++++++++++++++++ .../I2S_TxCallback/I2S_TxCallback.ino | 56 +++++++++++++++++++ libraries/CurieI2S/src/CurieI2S.cpp | 27 +++++++-- libraries/CurieI2S/src/CurieI2S.h | 22 ++++++-- 4 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino create mode 100644 libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino diff --git a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino new file mode 100644 index 00000000..d94f9483 --- /dev/null +++ b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino @@ -0,0 +1,53 @@ +/** + * A simple sketch to test the rx channel of the i2s interface. + * A callback function is used to fill up a buffer whenever data is received + * + * To test this sketch you will need a second Arduino/Genuino 101 board with the I2S_TxCallback sketch uploaded + * + * Connection: + * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) + * I2S_RWS(pin 3) -> I2S_TWS(pin 4) + * I2S_RXD(pin 5) -> I2S_TXD(pin 7) + * +**/ +#include + +uint32_t dataBuff[256]; +volatile int count = 0; + +void setup() +{ + // put your setup code here, to run once: + Serial.begin(115200); + while(!Serial); + Serial.println("CurieI2S Rx Callback Example"); + CurieI2S.begin(I2S_44K, I2S_32bit); + CurieI2S.setI2SMode(PHILIPS_MODE); + CurieI2S.attachRxInterrupt(rxDataReceived); + CurieI2S.initRX(); + CurieI2S.startRX(); + +} + +void loop() +{ + if(count>0) + { + for(int i =0; i < count; i++) + { + Serial.print("data: "); + Serial.println(dataBuff[i], HEX); + } + count = 0; + } + delay(500); +} + +//This function is called inside an ISR so it is important to make this as atomic/fast as possible +void rxDataReceived() +{ + while(CurieI2S.available()) + { + dataBuff[count++] = CurieI2S.requestdword(); + } +} diff --git a/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino b/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino new file mode 100644 index 00000000..cb3ff7cf --- /dev/null +++ b/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino @@ -0,0 +1,56 @@ +#include + +//I2S_TX -> Pin 7 +//I2S_TSK -> Pin 4 +//I2S_TSCK -> pin 2 + +void setup() +{ + Serial.begin(115200); + while(!Serial); + Serial.println("CurieI2S Tx Callback"); + CurieI2S.begin(I2S_44K, I2S_32bit); + CurieI2S.setI2SMode(PHILIPS_MODE); + CurieI2S.attachTxEmptyInterrupt(doneTX); + CurieI2S.attachTxInterrupt(fillTxBuffer); + CurieI2S.initTX(); +} + +void loop() +{ + Serial.println("+++"); + + //start filling the tx buffer + CurieI2S.pushData(0xFFFFFFFF); + CurieI2S.pushData(0x00000000); + CurieI2S.pushData(0xDEADFACE); + CurieI2S.pushData(0x10101010); + Serial.println("start transmitting"); + //Start Transmission + CurieI2S.startTX(); + for(int i = 0; i < 40; i++) + { + //keep filling the buffer + while(!CurieI2S.pushData(0xFFFFFFFF)); + while(!CurieI2S.pushData(0x00000000)); + while(!CurieI2S.pushData(0xDEADFACE)); + while(!CurieI2S.pushData(0x10101010)); + } + //Tx is automatically stopped after the tx buffer is emptied + + delay(500); + Serial.println("+++"); +} + +void doneTX() +{ + Serial.println("done transmitting"); +} + +void fillTxBuffer() +{ + //you can fill the tx buffer here if you want + //CurieI2S.pushData(0xDEADDEAD); + //CurieI2S.pushData(0xDEADFACE); +} + diff --git a/libraries/CurieI2S/src/CurieI2S.cpp b/libraries/CurieI2S/src/CurieI2S.cpp index 8eedbecd..27847736 100644 --- a/libraries/CurieI2S/src/CurieI2S.cpp +++ b/libraries/CurieI2S/src/CurieI2S.cpp @@ -47,7 +47,7 @@ static void i2sInterruptHandler(void) //Serial.println("rx almost full"); //disable RFIFO_AFULL interrupts - *I2S_CID_CTRL = *I2S_CID_CTRL & 0x7FFFFFFF; + //*I2S_CID_CTRL = *I2S_CID_CTRL & 0x7FFFFFFF; int index; int fifoDataLength = (*I2S_RFIFO_STAT & 0x0000000F); @@ -67,7 +67,7 @@ static void i2sInterruptHandler(void) #endif } - + //enable RFIFO_EMPTY interrupt *I2S_CID_CTRL = *I2S_CID_CTRL | 0x10000000; @@ -124,6 +124,9 @@ static void i2sInterruptHandler(void) //digitalWrite(I2S_DEBUG_PIN, LOW); #endif + //call tx callback + CurieI2S.i2s_tx_callback(); + if(_i2s_Tx_BufferPtr->head != _i2s_Tx_BufferPtr->tail) { int index = _i2s_Tx_BufferPtr->tail; @@ -227,8 +230,8 @@ static void i2sInterruptHandler(void) i2s_stat = i2s_stat & 0xFFFFF0FF; *I2S_STAT = i2s_stat | 0x00000001; - //call rx callback - CurieI2S.i2s_tx_callback(); + //call tx empty callback + CurieI2S.i2s_tx_empty_callback(); //enable TFIFO_AEMPTY and TFIFO_FULL interrupts *I2S_CID_CTRL = *I2S_CID_CTRL | 0x06000000; @@ -263,8 +266,9 @@ static void i2sInterruptHandler(void) Curie_I2S::Curie_I2S() { - i2s_txCB = NULL; i2s_rxCB = NULL; + i2s_txEmptyCB = NULL; + i2s_txCB = NULL; } void Curie_I2S::begin(uint32_t sampleRate, uint32_t resolution) @@ -391,7 +395,7 @@ void Curie_I2S::init() *I2S_CTRL = i2s_ctrl; //set threshold for FIFOs - *I2S_TFIFO_CTRL |= 0x00030003; + *I2S_TFIFO_CTRL |= 0x00030002; *I2S_RFIFO_CTRL |= 0x00010002; //enable interrupts @@ -633,6 +637,11 @@ void Curie_I2S::attachRxInterrupt(void (*userCallBack)()) i2s_rxCB = userCallBack; } +void Curie_I2S::attachTxEmptyInterrupt(void (*userCallBack)()) +{ + i2s_txEmptyCB = userCallBack; +} + void Curie_I2S::attachTxInterrupt(void (*userCallBack)()) { i2s_txCB = userCallBack; @@ -644,6 +653,12 @@ inline void Curie_I2S::i2s_rx_callback(void) i2s_rxCB(); } +inline void Curie_I2S::i2s_tx_empty_callback(void) +{ + if(i2s_txEmptyCB != NULL) + i2s_txEmptyCB(); +} + inline void Curie_I2S::i2s_tx_callback(void) { if(i2s_txCB != NULL) diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h index c7d1345f..5d60d978 100644 --- a/libraries/CurieI2S/src/CurieI2S.h +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -128,9 +128,11 @@ class Curie_I2S //enables i2s interrupts void enableInterrupts(); + void (*i2s_rxCB)(); + void (*i2s_txCB)(); - void (*i2s_rxCB)(); + void (*i2s_txEmptyCB)(); public: Curie_I2S(); @@ -200,21 +202,29 @@ class Curie_I2S uint8_t getRxFIFOLength(); - // Attach user callback when there is data pushed into the rx buffer from the RX_FIFO + // Attach user callback that is triggered when there is data pushed into the rx buffer from the RX_FIFO void attachRxInterrupt(void (*userCallBack)()); void detachRxInterrupt(void) { return attachTxInterrupt(NULL); }; - // Attach user callback when that gets called when TX_FIFO is empty(transmission done); + // Attach user callback that is triggered when that gets called when TX_FIFO is empty(transmission done); + void attachTxEmptyInterrupt(void (*userCallBack)()); + + void detachTxEmptyInterrupt(void) { return attachTxEmptyInterrupt(NULL); }; + + // Attach user callback that is triggered when that gets called when TX_FIFO has available space; void attachTxInterrupt(void (*userCallBack)()); - void detachTxInterrupt(void) { return attachRxInterrupt(NULL); }; + void detachTxInterrupt(void) { return attachTxInterrupt(NULL); }; + + //rx callback + void i2s_rx_callback(void); //tx callback void i2s_tx_callback(void); - //rx callback - void i2s_rx_callback(void); + //tx empty callback + void i2s_tx_empty_callback(void); }; extern Curie_I2S CurieI2S; From 0ad15b5a46969ddda239cf764caebb32a81e56ae Mon Sep 17 00:00:00 2001 From: "Bradford H. Needham" Date: Sun, 3 Apr 2016 11:07:14 -0700 Subject: [PATCH 021/222] Fixed spaces in keywords.txt; keywords now highlight properly --- libraries/CurieBLE/keywords.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/CurieBLE/keywords.txt b/libraries/CurieBLE/keywords.txt index 4598ecb2..85eccea2 100644 --- a/libraries/CurieBLE/keywords.txt +++ b/libraries/CurieBLE/keywords.txt @@ -49,10 +49,10 @@ written KEYWORD2 subscribed KEYWORD2 begin KEYWORD2 -getAdvertisingLength KEYWORD2 -getAdvertising KEYWORD2 +getAdvertisingLength KEYWORD2 +getAdvertising KEYWORD2 setAdvertisedServiceUuid KEYWORD2 -setAdvertisedServiceData KEYWORD2 +setAdvertisedServiceData KEYWORD2 setLocalName KEYWORD2 setAppearance KEYWORD2 setConnectionInterval KEYWORD2 From c1be134976c7afa8fd3af95907e0f043efc6bc8d Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Mon, 4 Apr 2016 10:17:29 -0700 Subject: [PATCH 022/222] CurieI2S - minor fixes/improvements -prevent buffer overflow in I2S_RxCallback example -calculate delay for any sample rate --- .../examples/I2S_RxCallback/I2S_RxCallback.ino | 1 + libraries/CurieI2S/src/CurieI2S.cpp | 11 ++++++++++- libraries/CurieI2S/src/CurieI2S.h | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino index d94f9483..1222f7f5 100644 --- a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino +++ b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino @@ -49,5 +49,6 @@ void rxDataReceived() while(CurieI2S.available()) { dataBuff[count++] = CurieI2S.requestdword(); + count %= 256; //prevent buffer overflow and just write data in front of the buffer. } } diff --git a/libraries/CurieI2S/src/CurieI2S.cpp b/libraries/CurieI2S/src/CurieI2S.cpp index 27847736..6179b34e 100644 --- a/libraries/CurieI2S/src/CurieI2S.cpp +++ b/libraries/CurieI2S/src/CurieI2S.cpp @@ -222,7 +222,8 @@ static void i2sInterruptHandler(void) //TXFIFO and tx buffer empty //last frame delay - delayTicks(960); + //delayTicks(960); + CurieI2S.lastFrameDelay(); //stop transmission *I2S_CTRL = *I2S_CTRL & 0xFDFFFFFE; @@ -357,6 +358,9 @@ void Curie_I2S::setSampleRate(uint32_t dividerValue) i2s_srr &= I2S_SAMPLERATE_MASK; i2s_srr |= dividerValue; *I2S_SRR = i2s_srr; + + //set frameDelay value. + frameDelay = (dividerValue&0x000000FF)*32*2; } void Curie_I2S::setResolution(uint32_t resolution) @@ -632,6 +636,11 @@ uint8_t Curie_I2S::getRxFIFOLength() return fifolength; } +void Curie_I2S::lastFrameDelay() +{ + delayTicks(frameDelay); +} + void Curie_I2S::attachRxInterrupt(void (*userCallBack)()) { i2s_rxCB = userCallBack; diff --git a/libraries/CurieI2S/src/CurieI2S.h b/libraries/CurieI2S/src/CurieI2S.h index 5d60d978..e7eb8894 100644 --- a/libraries/CurieI2S/src/CurieI2S.h +++ b/libraries/CurieI2S/src/CurieI2S.h @@ -96,6 +96,9 @@ class Curie_I2S { private: uint32_t clock; + + int frameDelay = 0; + bool useDMA; // initializes i2s interface @@ -202,6 +205,8 @@ class Curie_I2S uint8_t getRxFIFOLength(); + void lastFrameDelay(); + // Attach user callback that is triggered when there is data pushed into the rx buffer from the RX_FIFO void attachRxInterrupt(void (*userCallBack)()); From 669fb9bcf6e80d774a8a9d836b3354c5ddd04a99 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Mon, 4 Apr 2016 15:55:55 -0600 Subject: [PATCH 023/222] JIRA-558 Remove Intel Ethernet and SD libraries Signed-off-by: Brian Baltz --- libraries/Ethernet/README.adoc | 24 - .../AdvancedChatServer/AdvancedChatServer.ino | 108 -- .../BarometricPressureWebServer.ino | 223 --- .../examples/ChatServer/ChatServer.ino | 80 -- .../DhcpAddressPrinter/DhcpAddressPrinter.ino | 60 - .../DhcpChatServer/DhcpChatServer.ino | 88 -- .../examples/TelnetClient/TelnetClient.ino | 94 -- .../UDPSendReceiveString.ino | 119 -- .../examples/UdpNtpClient/UdpNtpClient.ino | 142 -- .../Ethernet/examples/WebClient/WebClient.ino | 88 -- .../WebClientRepeating/WebClientRepeating.ino | 108 -- .../Ethernet/examples/WebServer/WebServer.ino | 101 -- libraries/Ethernet/keywords.txt | 37 - libraries/Ethernet/library.properties | 9 - libraries/Ethernet/src/Dhcp.cpp | 481 ------- libraries/Ethernet/src/Dhcp.h | 178 --- libraries/Ethernet/src/Dns.cpp | 423 ------ libraries/Ethernet/src/Dns.h | 41 - libraries/Ethernet/src/Ethernet.cpp | 136 -- libraries/Ethernet/src/Ethernet.h | 43 - libraries/Ethernet/src/EthernetClient.cpp | 173 --- libraries/Ethernet/src/EthernetClient.h | 41 - libraries/Ethernet/src/EthernetServer.cpp | 92 -- libraries/Ethernet/src/EthernetServer.h | 22 - libraries/Ethernet/src/EthernetUdp.cpp | 218 --- libraries/Ethernet/src/EthernetUdp.h | 99 -- libraries/Ethernet/src/utility/socket.cpp | 469 ------ libraries/Ethernet/src/utility/socket.h | 44 - libraries/Ethernet/src/utility/util.h | 14 - libraries/Ethernet/src/utility/w5100.cpp | 225 --- libraries/Ethernet/src/utility/w5100.h | 418 ------ libraries/SD/README.adoc | 24 - libraries/SD/examples/CardInfo/CardInfo.ino | 111 -- .../SD/examples/Datalogger/Datalogger.ino | 84 -- libraries/SD/examples/DumpFile/DumpFile.ino | 65 - libraries/SD/examples/Files/Files.ino | 75 - libraries/SD/examples/ReadWrite/ReadWrite.ino | 79 -- libraries/SD/examples/listfiles/listfiles.ino | 80 -- libraries/SD/keywords.txt | 31 - libraries/SD/library.properties | 9 - libraries/SD/src/File.cpp | 146 -- libraries/SD/src/README.txt | 13 - libraries/SD/src/SD.cpp | 620 -------- libraries/SD/src/SD.h | 123 -- libraries/SD/src/utility/FatStructs.h | 418 ------ libraries/SD/src/utility/Sd2Card.cpp | 706 --------- libraries/SD/src/utility/Sd2Card.h | 240 ---- libraries/SD/src/utility/Sd2PinMap.h | 387 ----- libraries/SD/src/utility/SdFat.h | 551 ------- libraries/SD/src/utility/SdFatUtil.h | 75 - libraries/SD/src/utility/SdFatmainpage.h | 202 --- libraries/SD/src/utility/SdFile.cpp | 1263 ----------------- libraries/SD/src/utility/SdInfo.h | 232 --- libraries/SD/src/utility/SdVolume.cpp | 295 ---- 54 files changed, 10227 deletions(-) delete mode 100644 libraries/Ethernet/README.adoc delete mode 100644 libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino delete mode 100644 libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino delete mode 100644 libraries/Ethernet/examples/ChatServer/ChatServer.ino delete mode 100644 libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino delete mode 100644 libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino delete mode 100644 libraries/Ethernet/examples/TelnetClient/TelnetClient.ino delete mode 100644 libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino delete mode 100644 libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino delete mode 100644 libraries/Ethernet/examples/WebClient/WebClient.ino delete mode 100644 libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino delete mode 100644 libraries/Ethernet/examples/WebServer/WebServer.ino delete mode 100644 libraries/Ethernet/keywords.txt delete mode 100644 libraries/Ethernet/library.properties delete mode 100644 libraries/Ethernet/src/Dhcp.cpp delete mode 100644 libraries/Ethernet/src/Dhcp.h delete mode 100644 libraries/Ethernet/src/Dns.cpp delete mode 100644 libraries/Ethernet/src/Dns.h delete mode 100644 libraries/Ethernet/src/Ethernet.cpp delete mode 100644 libraries/Ethernet/src/Ethernet.h delete mode 100644 libraries/Ethernet/src/EthernetClient.cpp delete mode 100644 libraries/Ethernet/src/EthernetClient.h delete mode 100644 libraries/Ethernet/src/EthernetServer.cpp delete mode 100644 libraries/Ethernet/src/EthernetServer.h delete mode 100644 libraries/Ethernet/src/EthernetUdp.cpp delete mode 100644 libraries/Ethernet/src/EthernetUdp.h delete mode 100644 libraries/Ethernet/src/utility/socket.cpp delete mode 100644 libraries/Ethernet/src/utility/socket.h delete mode 100644 libraries/Ethernet/src/utility/util.h delete mode 100644 libraries/Ethernet/src/utility/w5100.cpp delete mode 100644 libraries/Ethernet/src/utility/w5100.h delete mode 100644 libraries/SD/README.adoc delete mode 100644 libraries/SD/examples/CardInfo/CardInfo.ino delete mode 100644 libraries/SD/examples/Datalogger/Datalogger.ino delete mode 100644 libraries/SD/examples/DumpFile/DumpFile.ino delete mode 100644 libraries/SD/examples/Files/Files.ino delete mode 100644 libraries/SD/examples/ReadWrite/ReadWrite.ino delete mode 100644 libraries/SD/examples/listfiles/listfiles.ino delete mode 100644 libraries/SD/keywords.txt delete mode 100644 libraries/SD/library.properties delete mode 100644 libraries/SD/src/File.cpp delete mode 100644 libraries/SD/src/README.txt delete mode 100644 libraries/SD/src/SD.cpp delete mode 100644 libraries/SD/src/SD.h delete mode 100644 libraries/SD/src/utility/FatStructs.h delete mode 100644 libraries/SD/src/utility/Sd2Card.cpp delete mode 100644 libraries/SD/src/utility/Sd2Card.h delete mode 100644 libraries/SD/src/utility/Sd2PinMap.h delete mode 100644 libraries/SD/src/utility/SdFat.h delete mode 100644 libraries/SD/src/utility/SdFatUtil.h delete mode 100644 libraries/SD/src/utility/SdFatmainpage.h delete mode 100644 libraries/SD/src/utility/SdFile.cpp delete mode 100644 libraries/SD/src/utility/SdInfo.h delete mode 100644 libraries/SD/src/utility/SdVolume.cpp diff --git a/libraries/Ethernet/README.adoc b/libraries/Ethernet/README.adoc deleted file mode 100644 index 8f890f04..00000000 --- a/libraries/Ethernet/README.adoc +++ /dev/null @@ -1,24 +0,0 @@ -= Ethernet Library for Arduino = - -With the Arduino Ethernet Shield, this library allows an Arduino board to connect to the internet. - -For more information about this library please visit us at -http://www.arduino.cc/en/Reference/Ethernet - -== License == - -Copyright (c) 2010 Arduino LLC. All right reserved. - -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 St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino deleted file mode 100644 index 6fa2787e..00000000 --- a/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino +++ /dev/null @@ -1,108 +0,0 @@ -/* - Advanced Chat Server - - A more advanced server that distributes any incoming messages - to all connected clients but the client the message comes from. - To use telnet to your device's IP address and type. - You can see the client's input in the serial monitor as well. - Using an Arduino Wiznet Ethernet shield. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - * Analog inputs attached to pins A0 through A5 (optional) - - created 18 Dec 2009 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - redesigned to make use of operator== 25 Nov 2013 - by Norbert Truchsess - - */ - -#include -#include - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network. -// gateway and subnet are optional: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -IPAddress ip(192,168,1, 177); -IPAddress gateway(192,168,1, 1); -IPAddress subnet(255, 255, 0, 0); - - -// telnet defaults to port 23 -EthernetServer server(23); - -EthernetClient clients[4]; - -void setup() { - // initialize the ethernet device - Ethernet.begin(mac, ip, gateway, subnet); - // start listening for clients - server.begin(); - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - Serial.print("Chat server address:"); - Serial.println(Ethernet.localIP()); -} - -void loop() { - // wait for a new client: - EthernetClient client = server.available(); - - // when the client sends the first byte, say hello: - if (client) { - - boolean newClient = true; - for (byte i=0;i<4;i++) { - //check whether this client refers to the same socket as one of the existing instances: - if (clients[i]==client) { - newClient = false; - break; - } - } - - if (newClient) { - //check which of the existing clients can be overridden: - for (byte i=0;i<4;i++) { - if (!clients[i] && clients[i]!=client) { - clients[i] = client; - // clead out the input buffer: - client.flush(); - Serial.println("We have a new client"); - client.print("Hello, client number: "); - client.print(i); - client.println(); - break; - } - } - } - - if (client.available() > 0) { - // read the bytes incoming from the client: - char thisChar = client.read(); - // echo the bytes back to all other connected clients: - for (byte i=0;i<4;i++) { - if (clients[i] && (clients[i]!=client)) { - clients[i].write(thisChar); - } - } - // echo the bytes to the server as well: - Serial.write(thisChar); - } - } - for (byte i=0;i<4;i++) { - if (!(clients[i].connected())) { - // client.stop() invalidates the internal socket-descriptor, so next use of == will allways return false; - clients[i].stop(); - } - } -} diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino deleted file mode 100644 index 2c85ddd7..00000000 --- a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino +++ /dev/null @@ -1,223 +0,0 @@ -/* - SCP1000 Barometric Pressure Sensor Display - - Serves the output of a Barometric Pressure Sensor as a web page. - Uses the SPI library. For details on the sensor, see: - http://www.sparkfun.com/commerce/product_info.php?products_id=8161 - http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ - - This sketch adapted from Nathan Seidle's SCP1000 example for PIC: - http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip - - Circuit: - SCP1000 sensor attached to pins 6,7, and 11 - 13: - DRDY: pin 6 - CSB: pin 7 - MOSI: pin 11 - MISO: pin 12 - SCK: pin 13 - - created 31 July 2010 - by Tom Igoe - */ - -#include -// the sensor communicates using SPI, so include the library: -#include - - -// assign a MAC address for the ethernet controller. -// fill in your address here: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -// assign an IP address for the controller: -IPAddress ip(192, 168, 1, 20); -IPAddress gateway(192, 168, 1, 1); -IPAddress subnet(255, 255, 255, 0); - - -// Initialize the Ethernet server library -// with the IP address and port you want to use -// (port 80 is default for HTTP): -EthernetServer server(80); - - -//Sensor's memory register addresses: -const int PRESSURE = 0x1F; //3 most significant bits of pressure -const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure -const int TEMPERATURE = 0x21; //16 bit temperature reading - -// pins used for the connection with the sensor -// the others you need are controlled by the SPI library): -const int dataReadyPin = 6; -const int chipSelectPin = 7; - -float temperature = 0.0; -long pressure = 0; -long lastReadingTime = 0; - -void setup() { - // start the SPI library: - SPI.begin(); - - // start the Ethernet connection and the server: - Ethernet.begin(mac, ip); - server.begin(); - - // initalize the data ready and chip select pins: - pinMode(dataReadyPin, INPUT); - pinMode(chipSelectPin, OUTPUT); - - Serial.begin(9600); - - //Configure SCP1000 for low noise configuration: - writeRegister(0x02, 0x2D); - writeRegister(0x01, 0x03); - writeRegister(0x03, 0x02); - - // give the sensor and Ethernet shield time to set up: - delay(1000); - - //Set the sensor to high resolution mode tp start readings: - writeRegister(0x03, 0x0A); - -} - -void loop() { - // check for a reading no more than once a second. - if (millis() - lastReadingTime > 1000) { - // if there's a reading ready, read it: - // don't do anything until the data ready pin is high: - if (digitalRead(dataReadyPin) == HIGH) { - getData(); - // timestamp the last time you got a reading: - lastReadingTime = millis(); - } - } - - // listen for incoming Ethernet connections: - listenForEthernetClients(); -} - - -void getData() { - Serial.println("Getting reading"); - //Read the temperature data - int tempData = readRegister(0x21, 2); - - // convert the temperature to celsius and display it: - temperature = (float)tempData / 20.0; - - //Read the pressure data highest 3 bits: - byte pressureDataHigh = readRegister(0x1F, 1); - pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0 - - //Read the pressure data lower 16 bits: - unsigned int pressureDataLow = readRegister(0x20, 2); - //combine the two parts into one 19-bit number: - pressure = ((pressureDataHigh << 16) | pressureDataLow) / 4; - - Serial.print("Temperature: "); - Serial.print(temperature); - Serial.println(" degrees C"); - Serial.print("Pressure: " + String(pressure)); - Serial.println(" Pa"); -} - -void listenForEthernetClients() { - // listen for incoming clients - EthernetClient client = server.available(); - if (client) { - Serial.println("Got a client"); - // an http request ends with a blank line - boolean currentLineIsBlank = true; - while (client.connected()) { - if (client.available()) { - char c = client.read(); - // if you've gotten to the end of the line (received a newline - // character) and the line is blank, the http request has ended, - // so you can send a reply - if (c == '\n' && currentLineIsBlank) { - // send a standard http response header - client.println("HTTP/1.1 200 OK"); - client.println("Content-Type: text/html"); - client.println(); - // print the current readings, in HTML format: - client.print("Temperature: "); - client.print(temperature); - client.print(" degrees C"); - client.println("
"); - client.print("Pressure: " + String(pressure)); - client.print(" Pa"); - client.println("
"); - break; - } - if (c == '\n') { - // you're starting a new line - currentLineIsBlank = true; - } - else if (c != '\r') { - // you've gotten a character on the current line - currentLineIsBlank = false; - } - } - } - // give the web browser time to receive the data - delay(1); - // close the connection: - client.stop(); - } -} - - -//Send a write command to SCP1000 -void writeRegister(byte registerName, byte registerValue) { - // SCP1000 expects the register name in the upper 6 bits - // of the byte: - registerName <<= 2; - // command (read or write) goes in the lower two bits: - registerName |= 0b00000010; //Write command - - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - - SPI.transfer(registerName); //Send register location - SPI.transfer(registerValue); //Send value to record into register - - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); -} - - -//Read register from the SCP1000: -unsigned int readRegister(byte registerName, int numBytes) { - byte inByte = 0; // incoming from the SPI read - unsigned int result = 0; // result to return - - // SCP1000 expects the register name in the upper 6 bits - // of the byte: - registerName <<= 2; - // command (read or write) goes in the lower two bits: - registerName &= 0b11111100; //Read command - - // take the chip select low to select the device: - digitalWrite(chipSelectPin, LOW); - // send the device the register you want to read: - int command = SPI.transfer(registerName); - // send a value of 0 to read the first byte returned: - inByte = SPI.transfer(0x00); - - result = inByte; - // if there's more than one byte returned, - // shift the first byte then get the second byte: - if (numBytes > 1) { - result = inByte << 8; - inByte = SPI.transfer(0x00); - result = result | inByte; - } - // take the chip select high to de-select: - digitalWrite(chipSelectPin, HIGH); - // return the result: - return(result); -} diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.ino b/libraries/Ethernet/examples/ChatServer/ChatServer.ino deleted file mode 100644 index 927a60e1..00000000 --- a/libraries/Ethernet/examples/ChatServer/ChatServer.ino +++ /dev/null @@ -1,80 +0,0 @@ -/* - Chat Server - - A simple server that distributes any incoming messages to all - connected clients. To use telnet to your device's IP address and type. - You can see the client's input in the serial monitor as well. - Using an Arduino Wiznet Ethernet shield. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - * Analog inputs attached to pins A0 through A5 (optional) - - created 18 Dec 2009 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - - */ - -#include -#include - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network. -// gateway and subnet are optional: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -IPAddress ip(192, 168, 1, 177); -IPAddress gateway(192, 168, 1, 1); -IPAddress subnet(255, 255, 0, 0); - - -// telnet defaults to port 23 -EthernetServer server(23); -boolean alreadyConnected = false; // whether or not the client was connected previously - -void setup() { - // initialize the ethernet device - Ethernet.begin(mac, ip, gateway, subnet); - // start listening for clients - server.begin(); - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - Serial.print("Chat server address:"); - Serial.println(Ethernet.localIP()); -} - -void loop() { - // wait for a new client: - EthernetClient client = server.available(); - - // when the client sends the first byte, say hello: - if (client) { - if (!alreadyConnected) { - // clead out the input buffer: - client.flush(); - Serial.println("We have a new client"); - client.println("Hello, client!"); - alreadyConnected = true; - } - - if (client.available() > 0) { - // read the bytes incoming from the client: - char thisChar = client.read(); - // echo the bytes back to the client: - server.write(thisChar); - // echo the bytes to the server as well: - Serial.write(thisChar); - } - } -} - - - diff --git a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino deleted file mode 100644 index a41b7740..00000000 --- a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino +++ /dev/null @@ -1,60 +0,0 @@ -/* - DHCP-based IP printer - - This sketch uses the DHCP extensions to the Ethernet library - to get an IP address via DHCP and print the address obtained. - using an Arduino Wiznet Ethernet shield. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - - created 12 April 2011 - modified 9 Apr 2012 - by Tom Igoe - - */ - -#include -#include - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { - 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 -}; - -// Initialize the Ethernet client library -// with the IP address and port of the server -// that you want to connect to (port 80 is default for HTTP): -EthernetClient client; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - // this check is only needed on the Leonardo: - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - // start the Ethernet connection: - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - // no point in carrying on, so do nothing forevermore: - for (;;) - ; - } - // print your local IP address: - Serial.print("My IP address: "); - for (byte thisByte = 0; thisByte < 4; thisByte++) { - // print the value of each byte of the IP address: - Serial.print(Ethernet.localIP()[thisByte], DEC); - Serial.print("."); - } - Serial.println(); -} - -void loop() { - -} - - diff --git a/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino b/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino deleted file mode 100644 index 73cde4bb..00000000 --- a/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino +++ /dev/null @@ -1,88 +0,0 @@ -/* - DHCP Chat Server - - A simple server that distributes any incoming messages to all - connected clients. To use telnet to your device's IP address and type. - You can see the client's input in the serial monitor as well. - Using an Arduino Wiznet Ethernet shield. - - THis version attempts to get an IP address using DHCP - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - - created 21 May 2011 - modified 9 Apr 2012 - by Tom Igoe - Based on ChatServer example by David A. Mellis - - */ - -#include -#include - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network. -// gateway and subnet are optional: -byte mac[] = { - 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 -}; -IPAddress ip(192, 168, 1, 177); -IPAddress gateway(192, 168, 1, 1); -IPAddress subnet(255, 255, 0, 0); - -// telnet defaults to port 23 -EthernetServer server(23); -boolean gotAMessage = false; // whether or not you got a message from the client yet - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - // this check is only needed on the Leonardo: - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - // start the Ethernet connection: - Serial.println("Trying to get an IP address using DHCP"); - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - // initialize the ethernet device not using DHCP: - Ethernet.begin(mac, ip, gateway, subnet); - } - // print your local IP address: - Serial.print("My IP address: "); - ip = Ethernet.localIP(); - for (byte thisByte = 0; thisByte < 4; thisByte++) { - // print the value of each byte of the IP address: - Serial.print(ip[thisByte], DEC); - Serial.print("."); - } - Serial.println(); - // start listening for clients - server.begin(); - -} - -void loop() { - // wait for a new client: - EthernetClient client = server.available(); - - // when the client sends the first byte, say hello: - if (client) { - if (!gotAMessage) { - Serial.println("We have a new client"); - client.println("Hello, client!"); - gotAMessage = true; - } - - // read the bytes incoming from the client: - char thisChar = client.read(); - // echo the bytes back to the client: - server.write(thisChar); - // echo the bytes to the server as well: - Serial.print(thisChar); - } -} - diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino b/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino deleted file mode 100644 index dcf3e8aa..00000000 --- a/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino +++ /dev/null @@ -1,94 +0,0 @@ -/* - Telnet client - - This sketch connects to a a telnet server (http://www.google.com) - using an Arduino Wiznet Ethernet shield. You'll need a telnet server - to test this with. - Processing's ChatServer example (part of the network library) works well, - running on port 10002. It can be found as part of the examples - in the Processing application, available at - http://processing.org/ - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - - created 14 Sep 2010 - modified 9 Apr 2012 - by Tom Igoe - - */ - -#include -#include - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -IPAddress ip(192, 168, 1, 177); - -// Enter the IP address of the server you're connecting to: -IPAddress server(1, 1, 1, 1); - -// Initialize the Ethernet client library -// with the IP address and port of the server -// that you want to connect to (port 23 is default for telnet; -// if you're using Processing's ChatServer, use port 10002): -EthernetClient client; - -void setup() { - // start the Ethernet connection: - Ethernet.begin(mac, ip); - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - // give the Ethernet shield a second to initialize: - delay(1000); - Serial.println("connecting..."); - - // if you get a connection, report back via serial: - if (client.connect(server, 10002)) { - Serial.println("connected"); - } - else { - // if you didn't get a connection to the server: - Serial.println("connection failed"); - } -} - -void loop() -{ - // if there are incoming bytes available - // from the server, read them and print them: - if (client.available()) { - char c = client.read(); - Serial.print(c); - } - - // as long as there are bytes in the serial queue, - // read them and send them out the socket if it's open: - while (Serial.available() > 0) { - char inChar = Serial.read(); - if (client.connected()) { - client.print(inChar); - } - } - - // if the server's disconnected, stop the client: - if (!client.connected()) { - Serial.println(); - Serial.println("disconnecting."); - client.stop(); - // do nothing: - while (true); - } -} - - - - diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino deleted file mode 100644 index 99de7650..00000000 --- a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino +++ /dev/null @@ -1,119 +0,0 @@ -/* - UDPSendReceive.pde: - This sketch receives UDP message strings, prints them to the serial port - and sends an "acknowledge" string back to the sender - - A Processing sketch is included at the end of file that can be used to send - and received messages for testing with a computer. - - created 21 Aug 2010 - by Michael Margolis - - This code is in the public domain. - */ - - -#include // needed for Arduino versions later than 0018 -#include -#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 - - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -IPAddress ip(192, 168, 1, 177); - -unsigned int localPort = 8888; // local port to listen on - -// buffers for receiving and sending data -char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, -char ReplyBuffer[] = "acknowledged"; // a string to send back - -// An EthernetUDP instance to let us send and receive packets over UDP -EthernetUDP Udp; - -void setup() { - // start the Ethernet and UDP: - Ethernet.begin(mac, ip); - Udp.begin(localPort); - - Serial.begin(9600); -} - -void loop() { - // if there's data available, read a packet - int packetSize = Udp.parsePacket(); - if (packetSize) - { - Serial.print("Received packet of size "); - Serial.println(packetSize); - Serial.print("From "); - IPAddress remote = Udp.remoteIP(); - for (int i = 0; i < 4; i++) - { - Serial.print(remote[i], DEC); - if (i < 3) - { - Serial.print("."); - } - } - Serial.print(", port "); - Serial.println(Udp.remotePort()); - - // read the packet into packetBufffer - Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); - Serial.println("Contents:"); - Serial.println(packetBuffer); - - // send a reply, to the IP address and port that sent us the packet we received - Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); - Udp.write(ReplyBuffer); - Udp.endPacket(); - } - delay(10); -} - - -/* - Processing sketch to run with this example - ===================================================== - - // Processing UDP example to send and receive string data from Arduino - // press any key to send the "Hello Arduino" message - - - import hypermedia.net.*; - - UDP udp; // define the UDP object - - - void setup() { - udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000 - //udp.log( true ); // <-- printout the connection activity - udp.listen( true ); // and wait for incoming message - } - - void draw() - { - } - - void keyPressed() { - String ip = "192.168.1.177"; // the remote IP address - int port = 8888; // the destination port - - udp.send("Hello World", ip, port ); // the message to send - - } - - void receive( byte[] data ) { // <-- default handler - //void receive( byte[] data, String ip, int port ) { // <-- extended handler - - for(int i=0; i < data.length; i++) - print(char(data[i])); - println(); - } - */ - - diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino deleted file mode 100644 index 25c71c40..00000000 --- a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino +++ /dev/null @@ -1,142 +0,0 @@ -/* - - Udp NTP Client - - Get the time from a Network Time Protocol (NTP) time server - Demonstrates use of UDP sendPacket and ReceivePacket - For more on NTP time servers and the messages needed to communicate with them, - see http://en.wikipedia.org/wiki/Network_Time_Protocol - - created 4 Sep 2010 - by Michael Margolis - modified 9 Apr 2012 - by Tom Igoe - - This code is in the public domain. - - */ - -#include -#include -#include - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; - -unsigned int localPort = 8888; // local port to listen for UDP packets - -char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server - -const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message - -byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets - -// A UDP instance to let us send and receive packets over UDP -EthernetUDP Udp; - -void setup() -{ - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - // start Ethernet and UDP - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - // no point in carrying on, so do nothing forevermore: - for (;;) - ; - } - Udp.begin(localPort); -} - -void loop() -{ - sendNTPpacket(timeServer); // send an NTP packet to a time server - - // wait to see if a reply is available - delay(1000); - if ( Udp.parsePacket() ) { - // We've received a packet, read the data from it - Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer - - //the timestamp starts at byte 40 of the received packet and is four bytes, - // or two words, long. First, esxtract the two words: - - unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); - unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); - // combine the four bytes (two words) into a long integer - // this is NTP time (seconds since Jan 1 1900): - unsigned long secsSince1900 = highWord << 16 | lowWord; - Serial.print("Seconds since Jan 1 1900 = " ); - Serial.println(secsSince1900); - - // now convert NTP time into everyday time: - Serial.print("Unix time = "); - // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: - const unsigned long seventyYears = 2208988800UL; - // subtract seventy years: - unsigned long epoch = secsSince1900 - seventyYears; - // print Unix time: - Serial.println(epoch); - - - // print the hour, minute and second: - Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) - Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) - Serial.print(':'); - if ( ((epoch % 3600) / 60) < 10 ) { - // In the first 10 minutes of each hour, we'll want a leading '0' - Serial.print('0'); - } - Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) - Serial.print(':'); - if ( (epoch % 60) < 10 ) { - // In the first 10 seconds of each minute, we'll want a leading '0' - Serial.print('0'); - } - Serial.println(epoch % 60); // print the second - } - // wait ten seconds before asking for the time again - delay(10000); -} - -// send an NTP request to the time server at the given address -unsigned long sendNTPpacket(char* address) -{ - // set all bytes in the buffer to 0 - memset(packetBuffer, 0, NTP_PACKET_SIZE); - // Initialize values needed to form NTP request - // (see URL above for details on the packets) - packetBuffer[0] = 0b11100011; // LI, Version, Mode - packetBuffer[1] = 0; // Stratum, or type of clock - packetBuffer[2] = 6; // Polling Interval - packetBuffer[3] = 0xEC; // Peer Clock Precision - // 8 bytes of zero for Root Delay & Root Dispersion - packetBuffer[12] = 49; - packetBuffer[13] = 0x4E; - packetBuffer[14] = 49; - packetBuffer[15] = 52; - - // all NTP fields have been given values, now - // you can send a packet requesting a timestamp: - Udp.beginPacket(address, 123); //NTP requests are to port 123 - Udp.write(packetBuffer, NTP_PACKET_SIZE); - Udp.endPacket(); -} - - - - - - - - - - diff --git a/libraries/Ethernet/examples/WebClient/WebClient.ino b/libraries/Ethernet/examples/WebClient/WebClient.ino deleted file mode 100644 index 9afd40ea..00000000 --- a/libraries/Ethernet/examples/WebClient/WebClient.ino +++ /dev/null @@ -1,88 +0,0 @@ -/* - Web client - - This sketch connects to a website (http://www.google.com) - using an Arduino Wiznet Ethernet shield. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - - created 18 Dec 2009 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe, based on work by Adrian McEwen - - */ - -#include -#include - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -// if you don't want to use DNS (and reduce your sketch size) -// use the numeric IP instead of the name for the server: -//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) -char server[] = "www.google.com"; // name address for Google (using DNS) - -// Set the static IP address to use if the DHCP fails to assign -IPAddress ip(192, 168, 0, 177); - -// Initialize the Ethernet client library -// with the IP address and port of the server -// that you want to connect to (port 80 is default for HTTP): -EthernetClient client; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - // start the Ethernet connection: - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - // no point in carrying on, so do nothing forevermore: - // try to congifure using IP address instead of DHCP: - Ethernet.begin(mac, ip); - } - // give the Ethernet shield a second to initialize: - delay(1000); - Serial.println("connecting..."); - - // if you get a connection, report back via serial: - if (client.connect(server, 80)) { - Serial.println("connected"); - // Make a HTTP request: - client.println("GET /search?q=arduino HTTP/1.1"); - client.println("Host: www.google.com"); - client.println("Connection: close"); - client.println(); - } - else { - // kf you didn't get a connection to the server: - Serial.println("connection failed"); - } -} - -void loop() -{ - // if there are incoming bytes available - // from the server, read them and print them: - if (client.available()) { - char c = client.read(); - Serial.print(c); - } - - // if the server's disconnected, stop the client: - if (!client.connected()) { - Serial.println(); - Serial.println("disconnecting."); - client.stop(); - - // do nothing forevermore: - while (true); - } -} - diff --git a/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino b/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino deleted file mode 100644 index ad3f461c..00000000 --- a/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino +++ /dev/null @@ -1,108 +0,0 @@ -/* - Repeating Web client - - This sketch connects to a a web server and makes a request - using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or - the Adafruit Ethernet shield, either one will work, as long as it's got - a Wiznet Ethernet module on board. - - This example uses DNS, by assigning the Ethernet client with a MAC address, - IP address, and DNS address. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - - created 19 Apr 2012 - by Tom Igoe - modified 21 Jan 2014 - by Federico Vanzati - - http://www.arduino.cc/en/Tutorial/WebClientRepeating - This code is in the public domain. - - */ - -#include -#include - -// assign a MAC address for the ethernet controller. -// fill in your address here: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -// fill in an available IP address on your network here, -// for manual configuration: -IPAddress ip(192, 168, 1, 177); - -// fill in your Domain Name Server address here: -IPAddress myDns(1, 1, 1, 1); - -// initialize the library instance: -EthernetClient client; - -char server[] = "www.arduino.cc"; -//IPAddress server(64,131,82,241); - -unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds -const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds -// the "L" is needed to use long type numbers - -void setup() { - // start serial port: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - // give the ethernet module time to boot up: - delay(1000); - // start the Ethernet connection using a fixed IP address and DNS server: - Ethernet.begin(mac, ip, myDns); - // print the Ethernet board/shield's IP address: - Serial.print("My IP address: "); - Serial.println(Ethernet.localIP()); -} - -void loop() { - // if there's incoming data from the net connection. - // send it out the serial port. This is for debugging - // purposes only: - if (client.available()) { - char c = client.read(); - Serial.write(c); - } - - // if ten seconds have passed since your last connection, - // then connect again and send data: - if (millis() - lastConnectionTime > postingInterval) { - httpRequest(); - } - -} - -// this method makes a HTTP connection to the server: -void httpRequest() { - // close any connection before send a new request. - // This will free the socket on the WiFi shield - client.stop(); - - // if there's a successful connection: - if (client.connect(server, 80)) { - Serial.println("connecting..."); - // send the HTTP PUT request: - client.println("GET /latest.txt HTTP/1.1"); - client.println("Host: www.arduino.cc"); - client.println("User-Agent: arduino-ethernet"); - client.println("Connection: close"); - client.println(); - - // note the time that the connection was made: - lastConnectionTime = millis(); - } - else { - // if you couldn't make a connection: - Serial.println("connection failed"); - } -} - - diff --git a/libraries/Ethernet/examples/WebServer/WebServer.ino b/libraries/Ethernet/examples/WebServer/WebServer.ino deleted file mode 100644 index d0c585d0..00000000 --- a/libraries/Ethernet/examples/WebServer/WebServer.ino +++ /dev/null @@ -1,101 +0,0 @@ -/* - Web Server - - A simple web server that shows the value of the analog input pins. - using an Arduino Wiznet Ethernet shield. - - Circuit: - * Ethernet shield attached to pins 10, 11, 12, 13 - * Analog inputs attached to pins A0 through A5 (optional) - - created 18 Dec 2009 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - - */ - -#include -#include - -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; -IPAddress ip(192, 168, 1, 177); - -// Initialize the Ethernet server library -// with the IP address and port you want to use -// (port 80 is default for HTTP): -EthernetServer server(80); - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } - - - // start the Ethernet connection and the server: - Ethernet.begin(mac, ip); - server.begin(); - Serial.print("server is at "); - Serial.println(Ethernet.localIP()); -} - - -void loop() { - // listen for incoming clients - EthernetClient client = server.available(); - if (client) { - Serial.println("new client"); - // an http request ends with a blank line - boolean currentLineIsBlank = true; - while (client.connected()) { - if (client.available()) { - char c = client.read(); - Serial.write(c); - // if you've gotten to the end of the line (received a newline - // character) and the line is blank, the http request has ended, - // so you can send a reply - if (c == '\n' && currentLineIsBlank) { - // send a standard http response header - client.println("HTTP/1.1 200 OK"); - client.println("Content-Type: text/html"); - client.println("Connection: close"); // the connection will be closed after completion of the response - client.println("Refresh: 5"); // refresh the page automatically every 5 sec - client.println(); - client.println(""); - client.println(""); - // output the value of each analog input pin - for (int analogChannel = 0; analogChannel < 6; analogChannel++) { - int sensorReading = analogRead(analogChannel); - client.print("analog input "); - client.print(analogChannel); - client.print(" is "); - client.print(sensorReading); - client.println("
"); - } - client.println(""); - break; - } - if (c == '\n') { - // you're starting a new line - currentLineIsBlank = true; - } - else if (c != '\r') { - // you've gotten a character on the current line - currentLineIsBlank = false; - } - } - } - // give the web browser time to receive the data - delay(1); - // close the connection: - client.stop(); - Serial.println("client disconnected"); - } -} - diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt deleted file mode 100644 index 7b162a54..00000000 --- a/libraries/Ethernet/keywords.txt +++ /dev/null @@ -1,37 +0,0 @@ -####################################### -# Syntax Coloring Map For Ethernet -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -Ethernet KEYWORD1 Ethernet -EthernetClient KEYWORD1 EthernetClient -EthernetServer KEYWORD1 EthernetServer -IPAddress KEYWORD1 EthernetIPAddress - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -status KEYWORD2 -connect KEYWORD2 -write KEYWORD2 -available KEYWORD2 -read KEYWORD2 -peek KEYWORD2 -flush KEYWORD2 -stop KEYWORD2 -connected KEYWORD2 -begin KEYWORD2 -beginPacket KEYWORD2 -endPacket KEYWORD2 -parsePacket KEYWORD2 -remoteIP KEYWORD2 -remotePort KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties deleted file mode 100644 index 9ea1c93c..00000000 --- a/libraries/Ethernet/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Ethernet -version=1.0.4 -author=Arduino -maintainer=Arduino -sentence=Enables network connection (local and Internet) using the Arduino Ethernet board or shield. For all Arduino boards. -paragraph=With this library you can use the Arduino Ethernet (shield or board) to connect to Internet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. -category=Communication -url=http://www.arduino.cc/en/Reference/Ethernet -architectures=arc32 diff --git a/libraries/Ethernet/src/Dhcp.cpp b/libraries/Ethernet/src/Dhcp.cpp deleted file mode 100644 index 4402bad6..00000000 --- a/libraries/Ethernet/src/Dhcp.cpp +++ /dev/null @@ -1,481 +0,0 @@ -// DHCP Library v0.3 - April 25, 2009 -// Author: Jordan Terrell - blog.jordanterrell.com - -#include "utility/w5100.h" - -#include -#include -#include "Dhcp.h" -#include "Arduino.h" -#include "utility/util.h" - -int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) -{ - _dhcpLeaseTime=0; - _dhcpT1=0; - _dhcpT2=0; - _lastCheck=0; - _timeout = timeout; - _responseTimeout = responseTimeout; - - // zero out _dhcpMacAddr - memset(_dhcpMacAddr, 0, 6); - reset_DHCP_lease(); - - memcpy((void*)_dhcpMacAddr, (void*)mac, 6); - _dhcp_state = STATE_DHCP_START; - return request_DHCP_lease(); -} - -void DhcpClass::reset_DHCP_lease(){ - // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp - memset(_dhcpLocalIp, 0, 20); -} - -//return:0 on error, 1 if request is sent and response is received -int DhcpClass::request_DHCP_lease(){ - - uint8_t messageType = 0; - - - - // Pick an initial transaction ID - _dhcpTransactionId = random(1UL, 2000UL); - _dhcpInitialTransactionId = _dhcpTransactionId; - - _dhcpUdpSocket.stop(); - if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) - { - // Couldn't get a socket - return 0; - } - - presend_DHCP(); - - int result = 0; - - unsigned long startTime = millis(); - - while(_dhcp_state != STATE_DHCP_LEASED) - { - if(_dhcp_state == STATE_DHCP_START) - { - _dhcpTransactionId++; - - send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); - _dhcp_state = STATE_DHCP_DISCOVER; - } - else if(_dhcp_state == STATE_DHCP_REREQUEST){ - _dhcpTransactionId++; - send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000)); - _dhcp_state = STATE_DHCP_REQUEST; - } - else if(_dhcp_state == STATE_DHCP_DISCOVER) - { - uint32_t respId; - messageType = parseDHCPResponse(_responseTimeout, respId); - if(messageType == DHCP_OFFER) - { - // We'll use the transaction ID that the offer came with, - // rather than the one we were up to - _dhcpTransactionId = respId; - send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); - _dhcp_state = STATE_DHCP_REQUEST; - } - } - else if(_dhcp_state == STATE_DHCP_REQUEST) - { - uint32_t respId; - messageType = parseDHCPResponse(_responseTimeout, respId); - if(messageType == DHCP_ACK) - { - _dhcp_state = STATE_DHCP_LEASED; - result = 1; - //use default lease time if we didn't get it - if(_dhcpLeaseTime == 0){ - _dhcpLeaseTime = DEFAULT_LEASE; - } - //calculate T1 & T2 if we didn't get it - if(_dhcpT1 == 0){ - //T1 should be 50% of _dhcpLeaseTime - _dhcpT1 = _dhcpLeaseTime >> 1; - } - if(_dhcpT2 == 0){ - //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime - _dhcpT2 = _dhcpT1 << 1; - } - _renewInSec = _dhcpT1; - _rebindInSec = _dhcpT2; - } - else if(messageType == DHCP_NAK) - _dhcp_state = STATE_DHCP_START; - } - - if(messageType == 255) - { - messageType = 0; - _dhcp_state = STATE_DHCP_START; - } - - if(result != 1 && ((millis() - startTime) > _timeout)) - break; - } - - // We're done with the socket now - _dhcpUdpSocket.stop(); - _dhcpTransactionId++; - - return result; -} - -void DhcpClass::presend_DHCP() -{ -} - -void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) -{ - uint8_t buffer[32]; - memset(buffer, 0, 32); - IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address - - if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) - { - // FIXME Need to return errors - return; - } - - buffer[0] = DHCP_BOOTREQUEST; // op - buffer[1] = DHCP_HTYPE10MB; // htype - buffer[2] = DHCP_HLENETHERNET; // hlen - buffer[3] = DHCP_HOPS; // hops - - // xid - unsigned long xid = htonl(_dhcpTransactionId); - memcpy(buffer + 4, &(xid), 4); - - // 8, 9 - seconds elapsed - buffer[8] = ((secondsElapsed & 0xff00) >> 8); - buffer[9] = (secondsElapsed & 0x00ff); - - // flags - unsigned short flags = htons(DHCP_FLAGSBROADCAST); - memcpy(buffer + 10, &(flags), 2); - - // ciaddr: already zeroed - // yiaddr: already zeroed - // siaddr: already zeroed - // giaddr: already zeroed - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 28); - - memset(buffer, 0, 32); // clear local buffer - - memcpy(buffer, _dhcpMacAddr, 6); // chaddr - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 16); - - memset(buffer, 0, 32); // clear local buffer - - // leave zeroed out for sname && file - // put in W5100 transmit buffer x 6 (192 bytes) - - for(int i = 0; i < 6; i++) { - _dhcpUdpSocket.write(buffer, 32); - } - - // OPT - Magic Cookie - buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); - buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); - buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); - buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); - - // OPT - message type - buffer[4] = dhcpMessageType; - buffer[5] = 0x01; - buffer[6] = messageType; //DHCP_REQUEST; - - // OPT - client identifier - buffer[7] = dhcpClientIdentifier; - buffer[8] = 0x07; - buffer[9] = 0x01; - memcpy(buffer + 10, _dhcpMacAddr, 6); - - // OPT - host name - buffer[16] = hostName; - buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address - strcpy((char*)&(buffer[18]), HOST_NAME); - - printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); - printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); - printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 30); - - if(messageType == DHCP_REQUEST) - { - buffer[0] = dhcpRequestedIPaddr; - buffer[1] = 0x04; - buffer[2] = _dhcpLocalIp[0]; - buffer[3] = _dhcpLocalIp[1]; - buffer[4] = _dhcpLocalIp[2]; - buffer[5] = _dhcpLocalIp[3]; - - buffer[6] = dhcpServerIdentifier; - buffer[7] = 0x04; - buffer[8] = _dhcpDhcpServerIp[0]; - buffer[9] = _dhcpDhcpServerIp[1]; - buffer[10] = _dhcpDhcpServerIp[2]; - buffer[11] = _dhcpDhcpServerIp[3]; - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 12); - } - - buffer[0] = dhcpParamRequest; - buffer[1] = 0x06; - buffer[2] = subnetMask; - buffer[3] = routersOnSubnet; - buffer[4] = dns; - buffer[5] = domainName; - buffer[6] = dhcpT1value; - buffer[7] = dhcpT2value; - buffer[8] = endOption; - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 9); - - _dhcpUdpSocket.endPacket(); -} - -uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) -{ - uint8_t type = 0; - uint8_t opt_len = 0; - - unsigned long startTime = millis(); - - while(_dhcpUdpSocket.parsePacket() <= 0) - { - if((millis() - startTime) > responseTimeout) - { - return 255; - } - delay(50); - } - // start reading in the packet - RIP_MSG_FIXED fixedMsg; - _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); - - if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) - { - transactionId = ntohl(fixedMsg.xid); - if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) - { - // Need to read the rest of the packet here regardless - _dhcpUdpSocket.flush(); - return 0; - } - - memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); - - // Skip to the option part - // Doing this a byte at a time so we don't have to put a big buffer - // on the stack (as we don't have lots of memory lying around) - for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) - { - _dhcpUdpSocket.read(); // we don't care about the returned byte - } - - while (_dhcpUdpSocket.available() > 0) - { - switch (_dhcpUdpSocket.read()) - { - case endOption : - break; - - case padOption : - break; - - case dhcpMessageType : - opt_len = _dhcpUdpSocket.read(); - type = _dhcpUdpSocket.read(); - break; - - case subnetMask : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpSubnetMask, 4); - break; - - case routersOnSubnet : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpGatewayIp, 4); - for (int i = 0; i < opt_len-4; i++) - { - _dhcpUdpSocket.read(); - } - break; - - case dns : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); - for (int i = 0; i < opt_len-4; i++) - { - _dhcpUdpSocket.read(); - } - break; - - case dhcpServerIdentifier : - opt_len = _dhcpUdpSocket.read(); - if ((_dhcpDhcpServerIp[0] == 0 && _dhcpDhcpServerIp[1] == 0 && - _dhcpDhcpServerIp[2] == 0 && _dhcpDhcpServerIp[3] == 0) || - IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) - { - _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); - } - else - { - // Skip over the rest of this option - while (opt_len--) - { - _dhcpUdpSocket.read(); - } - } - break; - - case dhcpT1value : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1)); - _dhcpT1 = ntohl(_dhcpT1); - break; - - case dhcpT2value : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2)); - _dhcpT2 = ntohl(_dhcpT2); - break; - - case dhcpIPaddrLeaseTime : - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); - _dhcpLeaseTime = ntohl(_dhcpLeaseTime); - _renewInSec = _dhcpLeaseTime; - break; - - default : - opt_len = _dhcpUdpSocket.read(); - // Skip over the rest of this option - while (opt_len--) - { - _dhcpUdpSocket.read(); - } - break; - } - } - } - - // Need to skip to end of the packet regardless here - _dhcpUdpSocket.flush(); - - return type; -} - - -/* - returns: - 0/DHCP_CHECK_NONE: nothing happened - 1/DHCP_CHECK_RENEW_FAIL: renew failed - 2/DHCP_CHECK_RENEW_OK: renew success - 3/DHCP_CHECK_REBIND_FAIL: rebind fail - 4/DHCP_CHECK_REBIND_OK: rebind success -*/ -int DhcpClass::checkLease(){ - //this uses a signed / unsigned trick to deal with millis overflow - unsigned long now = millis(); - signed long snow = (long)now; - int rc=DHCP_CHECK_NONE; - if (_lastCheck != 0){ - signed long factor; - //calc how many ms past the timeout we are - factor = snow - (long)_secTimeout; - //if on or passed the timeout, reduce the counters - if ( factor >= 0 ){ - //next timeout should be now plus 1000 ms minus parts of second in factor - _secTimeout = snow + 1000 - factor % 1000; - //how many seconds late are we, minimum 1 - factor = factor / 1000 +1; - - //reduce the counters by that mouch - //if we can assume that the cycle time (factor) is fairly constant - //and if the remainder is less than cycle time * 2 - //do it early instead of late - if(_renewInSec < factor*2 ) - _renewInSec = 0; - else - _renewInSec -= factor; - - if(_rebindInSec < factor*2 ) - _rebindInSec = 0; - else - _rebindInSec -= factor; - } - - //if we have a lease but should renew, do it - if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){ - _dhcp_state = STATE_DHCP_REREQUEST; - rc = 1 + request_DHCP_lease(); - } - - //if we have a lease or is renewing but should bind, do it - if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){ - //this should basically restart completely - _dhcp_state = STATE_DHCP_START; - reset_DHCP_lease(); - rc = 3 + request_DHCP_lease(); - } - } - else{ - _secTimeout = snow + 1000; - } - - _lastCheck = now; - return rc; -} - -IPAddress DhcpClass::getLocalIp() -{ - return IPAddress(_dhcpLocalIp); -} - -IPAddress DhcpClass::getSubnetMask() -{ - return IPAddress(_dhcpSubnetMask); -} - -IPAddress DhcpClass::getGatewayIp() -{ - return IPAddress(_dhcpGatewayIp); -} - -IPAddress DhcpClass::getDhcpServerIp() -{ - return IPAddress(_dhcpDhcpServerIp); -} - -IPAddress DhcpClass::getDnsServerIp() -{ - return IPAddress(_dhcpDnsServerIp); -} - -void DhcpClass::printByte(char * buf, uint8_t n ) { - char *str = &buf[1]; - buf[0]='0'; - do { - unsigned long m = n; - n /= 16; - char c = m - 16 * n; - *str-- = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); -} diff --git a/libraries/Ethernet/src/Dhcp.h b/libraries/Ethernet/src/Dhcp.h deleted file mode 100644 index f59c7e7f..00000000 --- a/libraries/Ethernet/src/Dhcp.h +++ /dev/null @@ -1,178 +0,0 @@ -// DHCP Library v0.3 - April 25, 2009 -// Author: Jordan Terrell - blog.jordanterrell.com - -#ifndef Dhcp_h -#define Dhcp_h - -#include "EthernetUdp.h" - -/* DHCP state machine. */ -#define STATE_DHCP_START 0 -#define STATE_DHCP_DISCOVER 1 -#define STATE_DHCP_REQUEST 2 -#define STATE_DHCP_LEASED 3 -#define STATE_DHCP_REREQUEST 4 -#define STATE_DHCP_RELEASE 5 - -#define DHCP_FLAGSBROADCAST 0x8000 - -/* UDP port numbers for DHCP */ -#define DHCP_SERVER_PORT 67 /* from server to client */ -#define DHCP_CLIENT_PORT 68 /* from client to server */ - -/* DHCP message OP code */ -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/* DHCP message type */ -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -#define DHCP_HTYPE10MB 1 -#define DHCP_HTYPE100MB 2 - -#define DHCP_HLENETHERNET 6 -#define DHCP_HOPS 0 -#define DHCP_SECS 0 - -#define MAGIC_COOKIE 0x63825363 -#define MAX_DHCP_OPT 16 - -#define HOST_NAME "WIZnet" -#define DEFAULT_LEASE (900) //default lease time in seconds - -#define DHCP_CHECK_NONE (0) -#define DHCP_CHECK_RENEW_FAIL (1) -#define DHCP_CHECK_RENEW_OK (2) -#define DHCP_CHECK_REBIND_FAIL (3) -#define DHCP_CHECK_REBIND_OK (4) - -enum -{ - padOption = 0, - subnetMask = 1, - timerOffset = 2, - routersOnSubnet = 3, - /* timeServer = 4, - nameServer = 5,*/ - dns = 6, - /*logServer = 7, - cookieServer = 8, - lprServer = 9, - impressServer = 10, - resourceLocationServer = 11,*/ - hostName = 12, - /*bootFileSize = 13, - meritDumpFile = 14,*/ - domainName = 15, - /*swapServer = 16, - rootPath = 17, - extentionsPath = 18, - IPforwarding = 19, - nonLocalSourceRouting = 20, - policyFilter = 21, - maxDgramReasmSize = 22, - defaultIPTTL = 23, - pathMTUagingTimeout = 24, - pathMTUplateauTable = 25, - ifMTU = 26, - allSubnetsLocal = 27, - broadcastAddr = 28, - performMaskDiscovery = 29, - maskSupplier = 30, - performRouterDiscovery = 31, - routerSolicitationAddr = 32, - staticRoute = 33, - trailerEncapsulation = 34, - arpCacheTimeout = 35, - ethernetEncapsulation = 36, - tcpDefaultTTL = 37, - tcpKeepaliveInterval = 38, - tcpKeepaliveGarbage = 39, - nisDomainName = 40, - nisServers = 41, - ntpServers = 42, - vendorSpecificInfo = 43, - netBIOSnameServer = 44, - netBIOSdgramDistServer = 45, - netBIOSnodeType = 46, - netBIOSscope = 47, - xFontServer = 48, - xDisplayManager = 49,*/ - dhcpRequestedIPaddr = 50, - dhcpIPaddrLeaseTime = 51, - /*dhcpOptionOverload = 52,*/ - dhcpMessageType = 53, - dhcpServerIdentifier = 54, - dhcpParamRequest = 55, - /*dhcpMsg = 56, - dhcpMaxMsgSize = 57,*/ - dhcpT1value = 58, - dhcpT2value = 59, - /*dhcpClassIdentifier = 60,*/ - dhcpClientIdentifier = 61, - endOption = 255 -}; - -typedef struct __attribute__((packed)) _RIP_MSG_FIXED -{ - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - uint32_t xid; - uint16_t secs; - uint16_t flags; - uint8_t ciaddr[4]; - uint8_t yiaddr[4]; - uint8_t siaddr[4]; - uint8_t giaddr[4]; - uint8_t chaddr[6]; -}RIP_MSG_FIXED; - -class DhcpClass { -private: - uint32_t _dhcpInitialTransactionId; - uint32_t _dhcpTransactionId; - uint8_t _dhcpMacAddr[6]; - uint8_t _dhcpLocalIp[4]; - uint8_t _dhcpSubnetMask[4]; - uint8_t _dhcpGatewayIp[4]; - uint8_t _dhcpDhcpServerIp[4]; - uint8_t _dhcpDnsServerIp[4]; - uint32_t _dhcpLeaseTime; - uint32_t _dhcpT1, _dhcpT2; - signed long _renewInSec; - signed long _rebindInSec; - signed long _lastCheck; - unsigned long _timeout; - unsigned long _responseTimeout; - unsigned long _secTimeout; - uint8_t _dhcp_state; - EthernetUDP _dhcpUdpSocket; - - int request_DHCP_lease(); - void reset_DHCP_lease(); - void presend_DHCP(); - void send_DHCP_MESSAGE(uint8_t, uint16_t); - void printByte(char *, uint8_t); - - uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); -public: - IPAddress getLocalIp(); - IPAddress getSubnetMask(); - IPAddress getGatewayIp(); - IPAddress getDhcpServerIp(); - IPAddress getDnsServerIp(); - - int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); - int checkLease(); -}; - -#endif diff --git a/libraries/Ethernet/src/Dns.cpp b/libraries/Ethernet/src/Dns.cpp deleted file mode 100644 index 62e36f8a..00000000 --- a/libraries/Ethernet/src/Dns.cpp +++ /dev/null @@ -1,423 +0,0 @@ -// Arduino DNS client for WizNet5100-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 - -#include "utility/w5100.h" -#include "EthernetUdp.h" -#include "utility/util.h" - -#include "Dns.h" -#include -//#include -#include "Arduino.h" - - -#define SOCKET_NONE 255 -// Various flags and header field values for a DNS message -#define UDP_HEADER_SIZE 8 -#define DNS_HEADER_SIZE 12 -#define TTL_SIZE 4 -#define QUERY_FLAG (0) -#define RESPONSE_FLAG (1<<15) -#define QUERY_RESPONSE_MASK (1<<15) -#define OPCODE_STANDARD_QUERY (0) -#define OPCODE_INVERSE_QUERY (1<<11) -#define OPCODE_STATUS_REQUEST (2<<11) -#define OPCODE_MASK (15<<11) -#define AUTHORITATIVE_FLAG (1<<10) -#define TRUNCATION_FLAG (1<<9) -#define RECURSION_DESIRED_FLAG (1<<8) -#define RECURSION_AVAILABLE_FLAG (1<<7) -#define RESP_NO_ERROR (0) -#define RESP_FORMAT_ERROR (1) -#define RESP_SERVER_FAILURE (2) -#define RESP_NAME_ERROR (3) -#define RESP_NOT_IMPLEMENTED (4) -#define RESP_REFUSED (5) -#define RESP_MASK (15) -#define TYPE_A (0x0001) -#define CLASS_IN (0x0001) -#define LABEL_COMPRESSION_MASK (0xC0) -// Port number that DNS servers listen on -#define DNS_PORT 53 - -// Possible return codes from ProcessResponse -#define SUCCESS 1 -#define TIMED_OUT -1 -#define INVALID_SERVER -2 -#define TRUNCATED -3 -#define INVALID_RESPONSE -4 - -void DNSClient::begin(const IPAddress& aDNSServer) -{ - iDNSServer = aDNSServer; - iRequestId = 0; -} - - -int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) -{ - // See if we've been given a valid IP address - const char* p =aIPAddrString; - while (*p && - ( (*p == '.') || (*p >= '0') || (*p <= '9') )) - { - p++; - } - - if (*p == '\0') - { - // It's looking promising, we haven't found any invalid characters - p = aIPAddrString; - int segment =0; - int segmentValue =0; - while (*p && (segment < 4)) - { - if (*p == '.') - { - // We've reached the end of a segment - if (segmentValue > 255) - { - // You can't have IP address segments that don't fit in a byte - return 0; - } - else - { - aResult[segment] = (byte)segmentValue; - segment++; - segmentValue = 0; - } - } - else - { - // Next digit - segmentValue = (segmentValue*10)+(*p - '0'); - } - p++; - } - // We've reached the end of address, but there'll still be the last - // segment to deal with - if ((segmentValue > 255) || (segment > 3)) - { - // You can't have IP address segments that don't fit in a byte, - // or more than four segments - return 0; - } - else - { - aResult[segment] = (byte)segmentValue; - return 1; - } - } - else - { - return 0; - } -} - -int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) -{ - int ret =0; - - // See if it's a numeric IP address - if (inet_aton(aHostname, aResult)) - { - // It is, our work here is done - return 1; - } - - // Check we've got a valid DNS server to use - if (iDNSServer == INADDR_NONE) - { - return INVALID_SERVER; - } - - // Find a socket to use - if (iUdp.begin(1024+(millis() & 0xF)) == 1) - { - // Try up to three times - int retries = 0; -// while ((retries < 3) && (ret <= 0)) - { - // Send DNS request - ret = iUdp.beginPacket(iDNSServer, DNS_PORT); - if (ret != 0) - { - // Now output the request data - ret = BuildRequest(aHostname); - if (ret != 0) - { - // And finally send the request - ret = iUdp.endPacket(); - if (ret != 0) - { - // Now wait for a response - int wait_retries = 0; - ret = TIMED_OUT; - while ((wait_retries < 3) && (ret == TIMED_OUT)) - { - ret = ProcessResponse(5000, aResult); - wait_retries++; - } - } - } - } - retries++; - } - - // We're done with the socket now - iUdp.stop(); - } - - return ret; -} - -uint16_t DNSClient::BuildRequest(const char* aName) -{ - // Build header - // 1 1 1 1 1 1 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ID | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | QDCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ANCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | NSCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ARCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // As we only support one request at a time at present, we can simplify - // some of this header - iRequestId = millis(); // generate a random ID - uint16_t twoByteBuffer; - - // FIXME We should also check that there's enough space available to write to, rather - // FIXME than assume there's enough space (as the code does at present) - iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); - - twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(1); // One question record - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = 0; // Zero answer records - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - // and zero additional records - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - // Build question - const char* start =aName; - const char* end =start; - uint8_t len; - // Run through the name being requested - while (*end) - { - // Find out how long this section of the name is - end = start; - while (*end && (*end != '.') ) - { - end++; - } - - if (end-start > 0) - { - // Write out the size of this section - len = end-start; - iUdp.write(&len, sizeof(len)); - // And then write out the section - iUdp.write((uint8_t*)start, end-start); - } - start = end+1; - } - - // We've got to the end of the question name, so - // terminate it with a zero-length section - len = 0; - iUdp.write(&len, sizeof(len)); - // Finally the type and class of question - twoByteBuffer = htons(TYPE_A); - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(CLASS_IN); // Internet class of question - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - // Success! Everything buffered okay - return 1; -} - - -uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) -{ - uint32_t startTime = millis(); - - // Wait for a response packet - while(iUdp.parsePacket() <= 0) - { - if((millis() - startTime) > aTimeout) - return TIMED_OUT; - delay(50); - } - - // We've had a reply! - // Read the UDP header - uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header - // Check that it's a response from the right server and the right port - if ( (iDNSServer != iUdp.remoteIP()) || - (iUdp.remotePort() != DNS_PORT) ) - { - // It's not from who we expected - return INVALID_SERVER; - } - - // Read through the rest of the response - if (iUdp.available() < DNS_HEADER_SIZE) - { - return TRUNCATED; - } - iUdp.read(header, DNS_HEADER_SIZE); - - uint16_t header_flags = htons(*((uint16_t*)&header[2])); - // Check that it's a response to this request - if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || - ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) - { - // Mark the entire packet as read - iUdp.flush(); - return INVALID_RESPONSE; - } - // Check for any errors in the response (or in our request) - // although we don't do anything to get round these - if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) - { - // Mark the entire packet as read - iUdp.flush(); - return -5; //INVALID_RESPONSE; - } - - // And make sure we've got (at least) one answer - uint16_t answerCount = htons(*((uint16_t*)&header[6])); - if (answerCount == 0 ) - { - // Mark the entire packet as read - iUdp.flush(); - return -6; //INVALID_RESPONSE; - } - - // Skip over any questions - for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) - { - // Skip over the name - uint8_t len; - do - { - iUdp.read(&len, sizeof(len)); - if (len > 0) - { - // Don't need to actually read the data out for the string, just - // advance ptr to beyond it - while(len--) - { - iUdp.read(); // we don't care about the returned byte - } - } - } while (len != 0); - - // Now jump over the type and class - for (int i =0; i < 4; i++) - { - iUdp.read(); // we don't care about the returned byte - } - } - - // Now we're up to the bit we're interested in, the answer - // There might be more than one answer (although we'll just use the first - // type A answer) and some authority and additional resource records but - // we're going to ignore all of them. - - for (uint16_t i =0; i < answerCount; i++) - { - // Skip the name - uint8_t len; - do - { - iUdp.read(&len, sizeof(len)); - if ((len & LABEL_COMPRESSION_MASK) == 0) - { - // It's just a normal label - if (len > 0) - { - // And it's got a length - // Don't need to actually read the data out for the string, - // just advance ptr to beyond it - while(len--) - { - iUdp.read(); // we don't care about the returned byte - } - } - } - else - { - // This is a pointer to a somewhere else in the message for the - // rest of the name. We don't care about the name, and RFC1035 - // says that a name is either a sequence of labels ended with a - // 0 length octet or a pointer or a sequence of labels ending in - // a pointer. Either way, when we get here we're at the end of - // the name - // Skip over the pointer - iUdp.read(); // we don't care about the returned byte - // And set len so that we drop out of the name loop - len = 0; - } - } while (len != 0); - - // Check the type and class - uint16_t answerType; - uint16_t answerClass; - iUdp.read((uint8_t*)&answerType, sizeof(answerType)); - iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); - - // Ignore the Time-To-Live as we don't do any caching - for (int i =0; i < TTL_SIZE; i++) - { - iUdp.read(); // we don't care about the returned byte - } - - // And read out the length of this answer - // Don't need header_flags anymore, so we can reuse it here - iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); - - if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) - { - if (htons(header_flags) != 4) - { - // It's a weird size - // Mark the entire packet as read - iUdp.flush(); - return -9;//INVALID_RESPONSE; - } - iUdp.read(aAddress.raw_address(), 4); - return SUCCESS; - } - else - { - // This isn't an answer type we're after, move onto the next one - for (uint16_t i =0; i < htons(header_flags); i++) - { - iUdp.read(); // we don't care about the returned byte - } - } - } - - // Mark the entire packet as read - iUdp.flush(); - - // If we get here then we haven't found an answer - return -10;//INVALID_RESPONSE; -} - diff --git a/libraries/Ethernet/src/Dns.h b/libraries/Ethernet/src/Dns.h deleted file mode 100644 index c99f5c37..00000000 --- a/libraries/Ethernet/src/Dns.h +++ /dev/null @@ -1,41 +0,0 @@ -// Arduino DNS client for WizNet5100-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 - -#ifndef DNSClient_h -#define DNSClient_h - -#include - -class DNSClient -{ -public: - // ctor - void begin(const IPAddress& aDNSServer); - - /** Convert a numeric IP address string into a four-byte IP address. - @param aIPAddrString IP address to convert - @param aResult IPAddress structure to store the returned IP address - @result 1 if aIPAddrString was successfully converted to an IP address, - else error code - */ - int inet_aton(const char *aIPAddrString, IPAddress& aResult); - - /** Resolve the given hostname to an IP address. - @param aHostname Name to be resolved - @param aResult IPAddress structure to store the returned IP address - @result 1 if aIPAddrString was successfully converted to an IP address, - else error code - */ - int getHostByName(const char* aHostname, IPAddress& aResult); - -protected: - uint16_t BuildRequest(const char* aName); - uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); - - IPAddress iDNSServer; - uint16_t iRequestId; - EthernetUDP iUdp; -}; - -#endif diff --git a/libraries/Ethernet/src/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp deleted file mode 100644 index 600471a7..00000000 --- a/libraries/Ethernet/src/Ethernet.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "utility/w5100.h" -#include "Ethernet.h" -#include "Dhcp.h" - -// XXX: don't make assumptions about the value of MAX_SOCK_NUM. -uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { - 0, 0, 0, 0 }; -uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { - 0, 0, 0, 0 }; - -int EthernetClass::begin(uint8_t *mac_address) -{ - - _dhcp = &s_dhcp; - - - // Initialise the basic info - W5100.init(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.setMACAddress(mac_address); - W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); - SPI.endTransaction(); - - // Now try to get our config info from a DHCP server - int ret = _dhcp->beginWithDHCP(mac_address); - if(ret == 1) - { - // We've successfully found a DHCP server and got our configuration info, so set things - // accordingly - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); - W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); - W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); - SPI.endTransaction(); - _dnsServerAddress = _dhcp->getDnsServerIp(); - } - - return ret; -} - -void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) -{ - // Assume the DNS server will be the machine on the same network as the local IP - // but with last octet being '1' - IPAddress dns_server = local_ip; - dns_server[3] = 1; - begin(mac_address, local_ip, dns_server); -} - -void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) -{ - // Assume the gateway will be the machine on the same network as the local IP - // but with last octet being '1' - IPAddress gateway = local_ip; - gateway[3] = 1; - begin(mac_address, local_ip, dns_server, gateway); -} - -void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) -{ - IPAddress subnet(255, 255, 255, 0); - begin(mac_address, local_ip, dns_server, gateway, subnet); -} - -void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) -{ - W5100.init(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.setMACAddress(mac); - W5100.setIPAddress(local_ip.raw_address()); - W5100.setGatewayIp(gateway.raw_address()); - W5100.setSubnetMask(subnet.raw_address()); - SPI.endTransaction(); - _dnsServerAddress = dns_server; -} - -int EthernetClass::maintain(){ - int rc = DHCP_CHECK_NONE; - if(_dhcp != NULL){ - //we have a pointer to dhcp, use it - rc = _dhcp->checkLease(); - switch ( rc ){ - case DHCP_CHECK_NONE: - //nothing done - break; - case DHCP_CHECK_RENEW_OK: - case DHCP_CHECK_REBIND_OK: - //we might have got a new IP. - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); - W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); - W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); - SPI.endTransaction(); - _dnsServerAddress = _dhcp->getDnsServerIp(); - break; - default: - //this is actually a error, it will retry though - break; - } - } - return rc; -} - -IPAddress EthernetClass::localIP() -{ - IPAddress ret; - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.getIPAddress(ret.raw_address()); - SPI.endTransaction(); - return ret; -} - -IPAddress EthernetClass::subnetMask() -{ - IPAddress ret; - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.getSubnetMask(ret.raw_address()); - SPI.endTransaction(); - return ret; -} - -IPAddress EthernetClass::gatewayIP() -{ - IPAddress ret; - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.getGatewayIp(ret.raw_address()); - SPI.endTransaction(); - return ret; -} - -IPAddress EthernetClass::dnsServerIP() -{ - return _dnsServerAddress; -} - -EthernetClass Ethernet; diff --git a/libraries/Ethernet/src/Ethernet.h b/libraries/Ethernet/src/Ethernet.h deleted file mode 100644 index 3ca2d6bc..00000000 --- a/libraries/Ethernet/src/Ethernet.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef ethernet_h -#define ethernet_h - -#include -//#include "w5100.h" -#include "IPAddress.h" -#include "EthernetClient.h" -#include "EthernetServer.h" -#include "Dhcp.h" - -#define MAX_SOCK_NUM 4 - -static DhcpClass s_dhcp; - -class EthernetClass { -private: - IPAddress _dnsServerAddress; - DhcpClass* _dhcp; -public: - static uint8_t _state[MAX_SOCK_NUM]; - static uint16_t _server_port[MAX_SOCK_NUM]; - // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the - // configuration through DHCP. - // Returns 0 if the DHCP configuration failed, and 1 if it succeeded - int begin(uint8_t *mac_address); - void begin(uint8_t *mac_address, IPAddress local_ip); - void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); - void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); - void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); - int maintain(); - - IPAddress localIP(); - IPAddress subnetMask(); - IPAddress gatewayIP(); - IPAddress dnsServerIP(); - - friend class EthernetClient; - friend class EthernetServer; -}; - -extern EthernetClass Ethernet; - -#endif diff --git a/libraries/Ethernet/src/EthernetClient.cpp b/libraries/Ethernet/src/EthernetClient.cpp deleted file mode 100644 index 1feed4c4..00000000 --- a/libraries/Ethernet/src/EthernetClient.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "utility/w5100.h" -#include "utility/socket.h" - -extern "C" { - #include "string.h" -} - -#include "Arduino.h" - -#include "Ethernet.h" -#include "EthernetClient.h" -#include "EthernetServer.h" -#include "Dns.h" - -uint16_t EthernetClient::_srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 - -EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) { -} - -EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) { -} - -int EthernetClient::connect(const char* host, uint16_t port) { - // Look up the host first - int ret = 0; - DNSClient dns; - IPAddress remote_addr; - - dns.begin(Ethernet.dnsServerIP()); - ret = dns.getHostByName(host, remote_addr); - if (ret == 1) { - return connect(remote_addr, port); - } else { - return ret; - } -} - -int EthernetClient::connect(IPAddress ip, uint16_t port) { - if (_sock != MAX_SOCK_NUM) - return 0; - - for (int i = 0; i < MAX_SOCK_NUM; i++) { - uint8_t s = socketStatus(i); - if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { - _sock = i; - break; - } - } - - if (_sock == MAX_SOCK_NUM) - return 0; - - _srcport++; - if (_srcport == 0) _srcport = 49152; //Use IANA recommended ephemeral port range 49152-65535 - socket(_sock, SnMR::TCP, _srcport, 0); - - if (!::connect(_sock, rawIPAddress(ip), port)) { - _sock = MAX_SOCK_NUM; - return 0; - } - - while (status() != SnSR::ESTABLISHED) { - delay(1); - if (status() == SnSR::CLOSED) { - _sock = MAX_SOCK_NUM; - return 0; - } - } - - return 1; -} - -size_t EthernetClient::write(uint8_t b) { - return write(&b, 1); -} - -size_t EthernetClient::write(const uint8_t *buf, size_t size) { - if (_sock == MAX_SOCK_NUM) { - setWriteError(); - return 0; - } - if (!send(_sock, buf, size)) { - setWriteError(); - return 0; - } - return size; -} - -int EthernetClient::available() { - if (_sock != MAX_SOCK_NUM) - return recvAvailable(_sock); - return 0; -} - -int EthernetClient::read() { - uint8_t b; - if ( recv(_sock, &b, 1) > 0 ) - { - // recv worked - return b; - } - else - { - // No data available - return -1; - } -} - -int EthernetClient::read(uint8_t *buf, size_t size) { - return recv(_sock, buf, size); -} - -int EthernetClient::peek() { - uint8_t b; - // Unlike recv, peek doesn't check to see if there's any data available, so we must - if (!available()) - return -1; - ::peek(_sock, &b); - return b; -} - -void EthernetClient::flush() { - ::flush(_sock); -} - -void EthernetClient::stop() { - if (_sock == MAX_SOCK_NUM) - return; - - // attempt to close the connection gracefully (send a FIN to other side) - disconnect(_sock); - unsigned long start = millis(); - - // wait up to a second for the connection to close - uint8_t s; - do { - s = status(); - if (s == SnSR::CLOSED) - break; // exit the loop - delay(1); - } while (millis() - start < 1000); - - // if it hasn't closed, close it forcefully - if (s != SnSR::CLOSED) - close(_sock); - - EthernetClass::_server_port[_sock] = 0; - _sock = MAX_SOCK_NUM; -} - -uint8_t EthernetClient::connected() { - if (_sock == MAX_SOCK_NUM) return 0; - - uint8_t s = status(); - return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT || - (s == SnSR::CLOSE_WAIT && !available())); -} - -uint8_t EthernetClient::status() { - if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; - return socketStatus(_sock); -} - -// the next function allows us to use the client returned by -// EthernetServer::available() as the condition in an if-statement. - -EthernetClient::operator bool() { - return _sock != MAX_SOCK_NUM; -} - -bool EthernetClient::operator==(const EthernetClient& rhs) { - return _sock == rhs._sock && _sock != MAX_SOCK_NUM && rhs._sock != MAX_SOCK_NUM; -} diff --git a/libraries/Ethernet/src/EthernetClient.h b/libraries/Ethernet/src/EthernetClient.h deleted file mode 100644 index 16e2500b..00000000 --- a/libraries/Ethernet/src/EthernetClient.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef ethernetclient_h -#define ethernetclient_h -#include "Arduino.h" -#include "Print.h" -#include "Client.h" -#include "IPAddress.h" - -class EthernetClient : public Client { - -public: - EthernetClient(); - EthernetClient(uint8_t sock); - - uint8_t status(); - virtual int connect(IPAddress ip, uint16_t port); - virtual int connect(const char *host, uint16_t port); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *buf, size_t size); - virtual int available(); - virtual int read(); - virtual int read(uint8_t *buf, size_t size); - virtual int peek(); - virtual void flush(); - virtual void stop(); - virtual uint8_t connected(); - virtual operator bool(); - virtual bool operator==(const bool value) { return bool() == value; } - virtual bool operator!=(const bool value) { return bool() != value; } - virtual bool operator==(const EthernetClient&); - virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; - - friend class EthernetServer; - - using Print::write; - -private: - static uint16_t _srcport; - uint8_t _sock; -}; - -#endif diff --git a/libraries/Ethernet/src/EthernetServer.cpp b/libraries/Ethernet/src/EthernetServer.cpp deleted file mode 100644 index cfa813eb..00000000 --- a/libraries/Ethernet/src/EthernetServer.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "utility/w5100.h" -#include "utility/socket.h" -extern "C" { -#include "string.h" -} - -#include "Ethernet.h" -#include "EthernetClient.h" -#include "EthernetServer.h" - -EthernetServer::EthernetServer(uint16_t port) -{ - _port = port; -} - -void EthernetServer::begin() -{ - for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - EthernetClient client(sock); - if (client.status() == SnSR::CLOSED) { - socket(sock, SnMR::TCP, _port, 0); - listen(sock); - EthernetClass::_server_port[sock] = _port; - break; - } - } -} - -void EthernetServer::accept() -{ - int listening = 0; - - for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - EthernetClient client(sock); - - if (EthernetClass::_server_port[sock] == _port) { - if (client.status() == SnSR::LISTEN) { - listening = 1; - } - else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) { - client.stop(); - } - } - } - - if (!listening) { - begin(); - } -} - -EthernetClient EthernetServer::available() -{ - accept(); - - for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - EthernetClient client(sock); - if (EthernetClass::_server_port[sock] == _port) { - uint8_t s = client.status(); - if (s == SnSR::ESTABLISHED || s == SnSR::CLOSE_WAIT) { - if (client.available()) { - // XXX: don't always pick the lowest numbered socket. - return client; - } - } - } - } - - return EthernetClient(MAX_SOCK_NUM); -} - -size_t EthernetServer::write(uint8_t b) -{ - return write(&b, 1); -} - -size_t EthernetServer::write(const uint8_t *buffer, size_t size) -{ - size_t n = 0; - - accept(); - - for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - EthernetClient client(sock); - - if (EthernetClass::_server_port[sock] == _port && - client.status() == SnSR::ESTABLISHED) { - n += client.write(buffer, size); - } - } - - return n; -} diff --git a/libraries/Ethernet/src/EthernetServer.h b/libraries/Ethernet/src/EthernetServer.h deleted file mode 100644 index 86ccafe9..00000000 --- a/libraries/Ethernet/src/EthernetServer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ethernetserver_h -#define ethernetserver_h - -#include "Server.h" - -class EthernetClient; - -class EthernetServer : -public Server { -private: - uint16_t _port; - void accept(); -public: - EthernetServer(uint16_t); - EthernetClient available(); - virtual void begin(); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *buf, size_t size); - using Print::write; -}; - -#endif diff --git a/libraries/Ethernet/src/EthernetUdp.cpp b/libraries/Ethernet/src/EthernetUdp.cpp deleted file mode 100644 index b5dcb78c..00000000 --- a/libraries/Ethernet/src/EthernetUdp.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. - * This version only offers minimal wrapping of socket.c/socket.h - * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ - * - * MIT License: - * Copyright (c) 2008 Bjoern Hartmann - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * bjoern@cs.stanford.edu 12/30/2008 - */ - -#include "utility/w5100.h" -#include "utility/socket.h" -#include "Ethernet.h" -#include "Udp.h" -#include "Dns.h" - -/* Constructor */ -EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} - -/* Start EthernetUDP socket, listening at local port PORT */ -uint8_t EthernetUDP::begin(uint16_t port) { - if (_sock != MAX_SOCK_NUM) - return 0; - - for (int i = 0; i < MAX_SOCK_NUM; i++) { - uint8_t s = socketStatus(i); - if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { - _sock = i; - break; - } - } - - if (_sock == MAX_SOCK_NUM) - return 0; - - _port = port; - _remaining = 0; - socket(_sock, SnMR::UDP, _port, 0); - - return 1; -} - -/* return number of bytes available in the current packet, - will return zero if parsePacket hasn't been called yet */ -int EthernetUDP::available() { - return _remaining; -} - -/* Release any resources being used by this EthernetUDP instance */ -void EthernetUDP::stop() -{ - if (_sock == MAX_SOCK_NUM) - return; - - close(_sock); - - EthernetClass::_server_port[_sock] = 0; - _sock = MAX_SOCK_NUM; -} - -int EthernetUDP::beginPacket(const char *host, uint16_t port) -{ - // Look up the host first - int ret = 0; - DNSClient dns; - IPAddress remote_addr; - - dns.begin(Ethernet.dnsServerIP()); - ret = dns.getHostByName(host, remote_addr); - if (ret == 1) { - return beginPacket(remote_addr, port); - } else { - return ret; - } -} - -int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) -{ - _offset = 0; - return startUDP(_sock, rawIPAddress(ip), port); -} - -int EthernetUDP::endPacket() -{ - return sendUDP(_sock); -} - -size_t EthernetUDP::write(uint8_t byte) -{ - return write(&byte, 1); -} - -size_t EthernetUDP::write(const uint8_t *buffer, size_t size) -{ - uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); - _offset += bytes_written; - return bytes_written; -} - -int EthernetUDP::parsePacket() -{ - // discard any remaining bytes in the last packet - flush(); - - if (recvAvailable(_sock) > 0) - { - //HACK - hand-parse the UDP packet using TCP recv method - uint8_t tmpBuf[8]; - int ret =0; - //read 8 header bytes and get IP and port from it - ret = recv(_sock,tmpBuf,8); - if (ret > 0) - { - _remoteIP = tmpBuf; - _remotePort = tmpBuf[4]; - _remotePort = (_remotePort << 8) + tmpBuf[5]; - _remaining = tmpBuf[6]; - _remaining = (_remaining << 8) + tmpBuf[7]; - - // When we get here, any remaining bytes are the data - ret = _remaining; - } - return ret; - } - // There aren't any packets available - return 0; -} - -int EthernetUDP::read() -{ - uint8_t byte; - - if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) - { - // We read things without any problems - _remaining--; - return byte; - } - - // If we get here, there's no data available - return -1; -} - -int EthernetUDP::read(unsigned char* buffer, size_t len) -{ - - if (_remaining > 0) - { - - int got; - - if (_remaining <= len) - { - // data should fit in the buffer - got = recv(_sock, buffer, _remaining); - } - else - { - // too much data for the buffer, - // grab as much as will fit - got = recv(_sock, buffer, len); - } - - if (got > 0) - { - _remaining -= got; - return got; - } - - } - - // If we get here, there's no data available or recv failed - return -1; - -} - -int EthernetUDP::peek() -{ - uint8_t b; - // Unlike recv, peek doesn't check to see if there's any data available, so we must. - // If the user hasn't called parsePacket yet then return nothing otherwise they - // may get the UDP header - if (!_remaining) - return -1; - ::peek(_sock, &b); - return b; -} - -void EthernetUDP::flush() -{ - // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? - // should only occur if recv fails after telling us the data is there, lets - // hope the w5100 always behaves :) - - while (_remaining) - { - read(); - } -} - diff --git a/libraries/Ethernet/src/EthernetUdp.h b/libraries/Ethernet/src/EthernetUdp.h deleted file mode 100644 index 8a6b7ab5..00000000 --- a/libraries/Ethernet/src/EthernetUdp.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. - * This version only offers minimal wrapping of socket.c/socket.h - * Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ - * - * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) - * 1) UDP does not guarantee the order in which assembled UDP packets are received. This - * might not happen often in practice, but in larger network topologies, a UDP - * packet can be received out of sequence. - * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being - * aware of it. Again, this may not be a concern in practice on small local networks. - * For more information, see http://www.cafeaulait.org/course/week12/35.html - * - * MIT License: - * Copyright (c) 2008 Bjoern Hartmann - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * bjoern@cs.stanford.edu 12/30/2008 - */ - -#ifndef ethernetudp_h -#define ethernetudp_h - -#include - -#define UDP_TX_PACKET_MAX_SIZE 24 - -class EthernetUDP : public UDP { -private: - uint8_t _sock; // socket ID for Wiz5100 - uint16_t _port; // local port to listen on - IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed - uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed - uint16_t _offset; // offset into the packet being sent - uint16_t _remaining; // remaining bytes of incoming packet yet to be processed - -public: - EthernetUDP(); // Constructor - virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - virtual void stop(); // Finish with the UDP socket - - // Sending UDP packets - - // Start building up a packet to send to the remote host specific in ip and port - // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port - virtual int beginPacket(IPAddress ip, uint16_t port); - // Start building up a packet to send to the remote host specific in host and port - // Returns 1 if successful, 0 if there was a problem resolving the hostname or port - virtual int beginPacket(const char *host, uint16_t port); - // Finish off this packet and send it - // Returns 1 if the packet was sent successfully, 0 if there was an error - virtual int endPacket(); - // Write a single byte into the packet - virtual size_t write(uint8_t); - // Write size bytes from buffer into the packet - virtual size_t write(const uint8_t *buffer, size_t size); - - using Print::write; - - // Start processing the next available incoming packet - // Returns the size of the packet in bytes, or 0 if no packets are available - virtual int parsePacket(); - // Number of bytes remaining in the current packet - virtual int available(); - // Read a single byte from the current packet - virtual int read(); - // Read up to len bytes from the current packet and place them into buffer - // Returns the number of bytes read, or 0 if none are available - virtual int read(unsigned char* buffer, size_t len); - // Read up to len characters from the current packet and place them into buffer - // Returns the number of characters read, or 0 if none are available - virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; - // Return the next byte from the current packet without moving on to the next byte - virtual int peek(); - virtual void flush(); // Finish reading the current packet - - // Return the IP address of the host who sent the current incoming packet - virtual IPAddress remoteIP() { return _remoteIP; }; - // Return the port of the host who sent the current incoming packet - virtual uint16_t remotePort() { return _remotePort; }; -}; - -#endif diff --git a/libraries/Ethernet/src/utility/socket.cpp b/libraries/Ethernet/src/utility/socket.cpp deleted file mode 100644 index 9254b743..00000000 --- a/libraries/Ethernet/src/utility/socket.cpp +++ /dev/null @@ -1,469 +0,0 @@ -#include "w5100.h" -#include "socket.h" - -static uint16_t local_port; - -/** - * @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it. - * @return 1 for success else 0. - */ -uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) -{ - if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) - { - close(s); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.writeSnMR(s, protocol | flag); - if (port != 0) { - W5100.writeSnPORT(s, port); - } - else { - local_port++; // if don't set the source port, set local_port number. - W5100.writeSnPORT(s, local_port); - } - - W5100.execCmdSn(s, Sock_OPEN); - SPI.endTransaction(); - return 1; - } - - return 0; -} - - -uint8_t socketStatus(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - uint8_t status = W5100.readSnSR(s); - SPI.endTransaction(); - return status; -} - - -/** - * @brief This function close the socket and parameter is "s" which represent the socket number - */ -void close(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.execCmdSn(s, Sock_CLOSE); - W5100.writeSnIR(s, 0xFF); - SPI.endTransaction(); -} - - -/** - * @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer. - * @return 1 for success else 0. - */ -uint8_t listen(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - if (W5100.readSnSR(s) != SnSR::INIT) { - SPI.endTransaction(); - return 0; - } - W5100.execCmdSn(s, Sock_LISTEN); - SPI.endTransaction(); - return 1; -} - - -/** - * @brief This function established the connection for the channel in Active (client) mode. - * This function waits for the untill the connection is established. - * - * @return 1 for success else 0. - */ -uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) -{ - if - ( - ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) || - ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || - (port == 0x00) - ) - return 0; - - // set destination IP - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.writeSnDIPR(s, addr); - W5100.writeSnDPORT(s, port); - W5100.execCmdSn(s, Sock_CONNECT); - SPI.endTransaction(); - - return 1; -} - - - -/** - * @brief This function used for disconnect the socket and parameter is "s" which represent the socket number - * @return 1 for success else 0. - */ -void disconnect(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.execCmdSn(s, Sock_DISCON); - SPI.endTransaction(); -} - - -/** - * @brief This function used to send the data in TCP mode - * @return 1 for success else 0. - */ -uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) -{ - uint8_t status=0; - uint16_t ret=0; - uint16_t freesize=0; - - if (len > W5100.SSIZE) - ret = W5100.SSIZE; // check size not to exceed MAX size. - else - ret = len; - - // if freebuf is available, start. - do - { - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - freesize = W5100.getTXFreeSize(s); - status = W5100.readSnSR(s); - SPI.endTransaction(); - if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) - { - ret = 0; - break; - } - yield(); - } - while (freesize < ret); - - // copy data - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.send_data_processing(s, (uint8_t *)buf, ret); - W5100.execCmdSn(s, Sock_SEND); - - /* +2008.01 bj */ - while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) - { - /* m2008.01 [bj] : reduce code */ - if ( W5100.readSnSR(s) == SnSR::CLOSED ) - { - SPI.endTransaction(); - close(s); - return 0; - } - SPI.endTransaction(); - yield(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - } - /* +2008.01 bj */ - W5100.writeSnIR(s, SnIR::SEND_OK); - SPI.endTransaction(); - return ret; -} - - -/** - * @brief This function is an application I/F function which is used to receive the data in TCP mode. - * It continues to wait for data as much as the application wants to receive. - * - * @return received data size for success else -1. - */ -int16_t recv(SOCKET s, uint8_t *buf, int16_t len) -{ - // Check how much data is available - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - int16_t ret = W5100.getRXReceivedSize(s); - if ( ret == 0 ) - { - // No data available. - uint8_t status = W5100.readSnSR(s); - if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT ) - { - // The remote end has closed its side of the connection, so this is the eof state - ret = 0; - } - else - { - // The connection is still up, but there's no data waiting to be read - ret = -1; - } - } - else if (ret > len) - { - ret = len; - } - - if ( ret > 0 ) - { - W5100.recv_data_processing(s, buf, ret); - W5100.execCmdSn(s, Sock_RECV); - } - SPI.endTransaction(); - return ret; -} - - -int16_t recvAvailable(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - int16_t ret = W5100.getRXReceivedSize(s); - SPI.endTransaction(); - return ret; -} - - -/** - * @brief Returns the first byte in the receive queue (no checking) - * - * @return - */ -uint16_t peek(SOCKET s, uint8_t *buf) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.recv_data_processing(s, buf, 1, 1); - SPI.endTransaction(); - return 1; -} - - -/** - * @brief This function is an application I/F function which is used to send the data for other then TCP mode. - * Unlike TCP transmission, The peer's destination address and the port is needed. - * - * @return This function return send data size for success else -1. - */ -uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port) -{ - uint16_t ret=0; - - if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size. - else ret = len; - - if - ( - ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || - ((port == 0x00)) ||(ret == 0) - ) - { - /* +2008.01 [bj] : added return value */ - ret = 0; - } - else - { - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.writeSnDIPR(s, addr); - W5100.writeSnDPORT(s, port); - - // copy data - W5100.send_data_processing(s, (uint8_t *)buf, ret); - W5100.execCmdSn(s, Sock_SEND); - - /* +2008.01 bj */ - while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) - { - if (W5100.readSnIR(s) & SnIR::TIMEOUT) - { - /* +2008.01 [bj]: clear interrupt */ - W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ - SPI.endTransaction(); - return 0; - } - SPI.endTransaction(); - yield(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - } - - /* +2008.01 bj */ - W5100.writeSnIR(s, SnIR::SEND_OK); - SPI.endTransaction(); - } - return ret; -} - - -/** - * @brief This function is an application I/F function which is used to receive the data in other then - * TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well. - * - * @return This function return received data size for success else -1. - */ -uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port) -{ - uint8_t head[8]; - uint16_t data_len=0; - uint16_t ptr=0; - - if ( len > 0 ) - { - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - ptr = W5100.readSnRX_RD(s); - switch (W5100.readSnMR(s) & 0x07) - { - case SnMR::UDP : - W5100.read_data(s, ptr, head, 0x08); - ptr += 8; - // read peer's IP address, port number. - addr[0] = head[0]; - addr[1] = head[1]; - addr[2] = head[2]; - addr[3] = head[3]; - *port = head[4]; - *port = (*port << 8) + head[5]; - data_len = head[6]; - data_len = (data_len << 8) + head[7]; - - W5100.read_data(s, ptr, buf, data_len); // data copy. - ptr += data_len; - - W5100.writeSnRX_RD(s, ptr); - break; - - case SnMR::IPRAW : - W5100.read_data(s, ptr, head, 0x06); - ptr += 6; - - addr[0] = head[0]; - addr[1] = head[1]; - addr[2] = head[2]; - addr[3] = head[3]; - data_len = head[4]; - data_len = (data_len << 8) + head[5]; - - W5100.read_data(s, ptr, buf, data_len); // data copy. - ptr += data_len; - - W5100.writeSnRX_RD(s, ptr); - break; - - case SnMR::MACRAW: - W5100.read_data(s, ptr, head, 2); - ptr+=2; - data_len = head[0]; - data_len = (data_len<<8) + head[1] - 2; - - W5100.read_data(s, ptr, buf, data_len); - ptr += data_len; - W5100.writeSnRX_RD(s, ptr); - break; - - default : - break; - } - W5100.execCmdSn(s, Sock_RECV); - SPI.endTransaction(); - } - return data_len; -} - -/** - * @brief Wait for buffered transmission to complete. - */ -void flush(SOCKET s) { - // TODO -} - -uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) -{ - uint16_t ret=0; - - if (len > W5100.SSIZE) - ret = W5100.SSIZE; // check size not to exceed MAX size. - else - ret = len; - - if (ret == 0) - return 0; - - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.send_data_processing(s, (uint8_t *)buf, ret); - W5100.execCmdSn(s, Sock_SEND); - - while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) - { - if (W5100.readSnIR(s) & SnIR::TIMEOUT) - { - /* in case of igmp, if send fails, then socket closed */ - /* if you want change, remove this code. */ - SPI.endTransaction(); - close(s); - return 0; - } - SPI.endTransaction(); - yield(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - } - - W5100.writeSnIR(s, SnIR::SEND_OK); - SPI.endTransaction(); - return ret; -} - -uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) -{ - uint16_t ret =0; - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - if (len > W5100.getTXFreeSize(s)) - { - ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. - } - else - { - ret = len; - } - W5100.send_data_processing_offset(s, offset, buf, ret); - SPI.endTransaction(); - return ret; -} - -int startUDP(SOCKET s, uint8_t* addr, uint16_t port) -{ - if - ( - ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || - ((port == 0x00)) - ) - { - return 0; - } - else - { - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.writeSnDIPR(s, addr); - W5100.writeSnDPORT(s, port); - SPI.endTransaction(); - return 1; - } -} - -int sendUDP(SOCKET s) -{ - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - W5100.execCmdSn(s, Sock_SEND); - - /* +2008.01 bj */ - while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) - { - if (W5100.readSnIR(s) & SnIR::TIMEOUT) - { - /* +2008.01 [bj]: clear interrupt */ - W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); - SPI.endTransaction(); - return 0; - } - SPI.endTransaction(); - yield(); - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - } - - /* +2008.01 bj */ - W5100.writeSnIR(s, SnIR::SEND_OK); - SPI.endTransaction(); - - /* Sent ok */ - return 1; -} - diff --git a/libraries/Ethernet/src/utility/socket.h b/libraries/Ethernet/src/utility/socket.h deleted file mode 100644 index 37ba8542..00000000 --- a/libraries/Ethernet/src/utility/socket.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _SOCKET_H_ -#define _SOCKET_H_ - -#include "utility/w5100.h" - -extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) -extern uint8_t socketStatus(SOCKET s); -extern void close(SOCKET s); // Close socket -extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) -extern void disconnect(SOCKET s); // disconnect the connection -extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection) -extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) -extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP) -extern int16_t recvAvailable(SOCKET s); -extern uint16_t peek(SOCKET s, uint8_t *buf); -extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) -extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) -extern void flush(SOCKET s); // Wait for transmission to complete - -extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); - -// Functions to allow buffered UDP send (i.e. where the UDP datagram is built up over a -// number of calls before being sent -/* - @brief This function sets up a UDP datagram, the data for which will be provided by one - or more calls to bufferData and then finally sent with sendUDP. - @return 1 if the datagram was successfully set up, or 0 if there was an error -*/ -extern int startUDP(SOCKET s, uint8_t* addr, uint16_t port); -/* - @brief This function copies up to len bytes of data from buf into a UDP datagram to be - sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. - @return Number of bytes successfully buffered -*/ -uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len); -/* - @brief Send a UDP datagram built up from a sequence of startUDP followed by one or more - calls to bufferData. - @return 1 if the datagram was successfully sent, or 0 if there was an error -*/ -int sendUDP(SOCKET s); - -#endif -/* _SOCKET_H_ */ diff --git a/libraries/Ethernet/src/utility/util.h b/libraries/Ethernet/src/utility/util.h deleted file mode 100644 index 33d32a97..00000000 --- a/libraries/Ethernet/src/utility/util.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#define htons(x) ( ((x)<< 8 & 0xFF00) | \ - ((x)>> 8 & 0x00FF) ) -#define ntohs(x) htons(x) - -#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ - ((x)<< 8 & 0x00FF0000UL) | \ - ((x)>> 8 & 0x0000FF00UL) | \ - ((x)>>24 & 0x000000FFUL) ) -#define ntohl(x) htonl(x) - -#endif diff --git a/libraries/Ethernet/src/utility/w5100.cpp b/libraries/Ethernet/src/utility/w5100.cpp deleted file mode 100644 index edf830e9..00000000 --- a/libraries/Ethernet/src/utility/w5100.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2010 by Arduino LLC. All rights reserved. - * - * 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 -#include - -#include "w5100.h" - -// W5100 controller instance -W5100Class W5100; - -#define TX_RX_MAX_BUF_SIZE 2048 -#define TX_BUF 0x1100 -#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) - -#define TXBUF_BASE 0x4000 -#define RXBUF_BASE 0x6000 - -void W5100Class::init(void) -{ - delay(300); - -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) - SPI.begin(); - initSS(); -#else - SPI.begin(SPI_CS); - // Set clock to 4Mhz (W5100 should support up to about 14Mhz) - SPI.setClockDivider(SPI_CS, 21); - SPI.setDataMode(SPI_CS, SPI_MODE0); -#endif - SPI.beginTransaction(SPI_ETHERNET_SETTINGS); - writeMR(1< SSIZE) - { - // Wrap around circular buffer - uint16_t size = SSIZE - offset; - write(dstAddr, data, size); - write(SBASE[s], data + size, len - size); - } - else { - write(dstAddr, data, len); - } - - ptr += len; - writeSnTX_WR(s, ptr); -} - - -void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) -{ - uint16_t ptr; - ptr = readSnRX_RD(s); - read_data(s, ptr, data, len); - if (!peek) - { - ptr += len; - writeSnRX_RD(s, ptr); - } -} - -void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len) -{ - uint16_t size; - uint16_t src_mask; - uint16_t src_ptr; - - src_mask = src & RMASK; - src_ptr = RBASE[s] + src_mask; - - if( (src_mask + len) > RSIZE ) - { - size = RSIZE - src_mask; - read(src_ptr, (uint8_t *)dst, size); - dst += size; - read(RBASE[s], (uint8_t *) dst, len - size); - } - else - read(src_ptr, (uint8_t *) dst, len); -} - - -uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) -{ -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) - setSS(); - SPI.transfer(0xF0); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - SPI.transfer(_data); - resetSS(); -#else - SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); - SPI.transfer(SPI_CS, _data); -#endif - return 1; -} - -uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) -{ - for (uint16_t i=0; i<_len; i++) - { -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) - setSS(); - SPI.transfer(0xF0); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - _addr++; - SPI.transfer(_buf[i]); - resetSS(); -#else - SPI.transfer(SPI_CS, 0xF0, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); - SPI.transfer(SPI_CS, _buf[i]); - _addr++; -#endif - } - return _len; -} - -uint8_t W5100Class::read(uint16_t _addr) -{ -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) - setSS(); - SPI.transfer(0x0F); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - uint8_t _data = SPI.transfer(0); - resetSS(); -#else - SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); - uint8_t _data = SPI.transfer(SPI_CS, 0); -#endif - return _data; -} - -uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) -{ - for (uint16_t i=0; i<_len; i++) - { -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) - setSS(); - SPI.transfer(0x0F); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - _addr++; - _buf[i] = SPI.transfer(0); - resetSS(); -#else - SPI.transfer(SPI_CS, 0x0F, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr >> 8, SPI_CONTINUE); - SPI.transfer(SPI_CS, _addr & 0xFF, SPI_CONTINUE); - _buf[i] = SPI.transfer(SPI_CS, 0); - _addr++; -#endif - } - return _len; -} - -void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { - // Send command to socket - writeSnCR(s, _cmd); - // Wait for command to complete - while (readSnCR(s)) - ; -} diff --git a/libraries/Ethernet/src/utility/w5100.h b/libraries/Ethernet/src/utility/w5100.h deleted file mode 100644 index 6c272081..00000000 --- a/libraries/Ethernet/src/utility/w5100.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2010 by Arduino LLC. All rights reserved. - * - * 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 W5100_H_INCLUDED -#define W5100_H_INCLUDED - -#include - -#define SPI_CS 10 - -#if (defined(ARDUINO_ARCH_AVR) || defined(__ARDUINO_ARC__)) -#define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0) -#else -#define SPI_ETHERNET_SETTINGS SPI_CS,SPISettings(4000000, MSBFIRST, SPI_MODE0) -#endif - -#define MAX_SOCK_NUM 4 - -typedef uint8_t SOCKET; - -#define IDM_OR 0x8000 -#define IDM_AR0 0x8001 -#define IDM_AR1 0x8002 -#define IDM_DR 0x8003 -/* -class MR { -public: - static const uint8_t RST = 0x80; - static const uint8_t PB = 0x10; - static const uint8_t PPPOE = 0x08; - static const uint8_t LB = 0x04; - static const uint8_t AI = 0x02; - static const uint8_t IND = 0x01; -}; -*/ -/* -class IR { -public: - static const uint8_t CONFLICT = 0x80; - static const uint8_t UNREACH = 0x40; - static const uint8_t PPPoE = 0x20; - static const uint8_t SOCK0 = 0x01; - static const uint8_t SOCK1 = 0x02; - static const uint8_t SOCK2 = 0x04; - static const uint8_t SOCK3 = 0x08; - static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); }; -}; -*/ - -class SnMR { -public: - static const uint8_t CLOSE = 0x00; - static const uint8_t TCP = 0x01; - static const uint8_t UDP = 0x02; - static const uint8_t IPRAW = 0x03; - static const uint8_t MACRAW = 0x04; - static const uint8_t PPPOE = 0x05; - static const uint8_t ND = 0x20; - static const uint8_t MULTI = 0x80; -}; - -enum SockCMD { - Sock_OPEN = 0x01, - Sock_LISTEN = 0x02, - Sock_CONNECT = 0x04, - Sock_DISCON = 0x08, - Sock_CLOSE = 0x10, - Sock_SEND = 0x20, - Sock_SEND_MAC = 0x21, - Sock_SEND_KEEP = 0x22, - Sock_RECV = 0x40 -}; - -/*class SnCmd { -public: - static const uint8_t OPEN = 0x01; - static const uint8_t LISTEN = 0x02; - static const uint8_t CONNECT = 0x04; - static const uint8_t DISCON = 0x08; - static const uint8_t CLOSE = 0x10; - static const uint8_t SEND = 0x20; - static const uint8_t SEND_MAC = 0x21; - static const uint8_t SEND_KEEP = 0x22; - static const uint8_t RECV = 0x40; -}; -*/ - -class SnIR { -public: - static const uint8_t SEND_OK = 0x10; - static const uint8_t TIMEOUT = 0x08; - static const uint8_t RECV = 0x04; - static const uint8_t DISCON = 0x02; - static const uint8_t CON = 0x01; -}; - -class SnSR { -public: - static const uint8_t CLOSED = 0x00; - static const uint8_t INIT = 0x13; - static const uint8_t LISTEN = 0x14; - static const uint8_t SYNSENT = 0x15; - static const uint8_t SYNRECV = 0x16; - static const uint8_t ESTABLISHED = 0x17; - static const uint8_t FIN_WAIT = 0x18; - static const uint8_t CLOSING = 0x1A; - static const uint8_t TIME_WAIT = 0x1B; - static const uint8_t CLOSE_WAIT = 0x1C; - static const uint8_t LAST_ACK = 0x1D; - static const uint8_t UDP = 0x22; - static const uint8_t IPRAW = 0x32; - static const uint8_t MACRAW = 0x42; - static const uint8_t PPPOE = 0x5F; -}; - -class IPPROTO { -public: - static const uint8_t IP = 0; - static const uint8_t ICMP = 1; - static const uint8_t IGMP = 2; - static const uint8_t GGP = 3; - static const uint8_t TCP = 6; - static const uint8_t PUP = 12; - static const uint8_t UDP = 17; - static const uint8_t IDP = 22; - static const uint8_t ND = 77; - static const uint8_t RAW = 255; -}; - -class W5100Class { - -public: - void init(); - - /** - * @brief This function is being used for copy the data form Receive buffer of the chip to application buffer. - * - * It calculate the actual physical address where one has to read - * the data from Receive buffer. Here also take care of the condition while it exceed - * the Rx memory uper-bound of socket. - */ - void read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len); - - /** - * @brief This function is being called by send() and sendto() function also. - * - * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer - * register. User should read upper byte first and lower byte later to get proper value. - */ - void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); - /** - * @brief A copy of send_data_processing that uses the provided ptr for the - * write offset. Only needed for the "streaming" UDP API, where - * a single UDP packet is built up over a number of calls to - * send_data_processing_ptr, because TX_WR doesn't seem to get updated - * correctly in those scenarios - * @param ptr value to use in place of TX_WR. If 0, then the value is read - * in from TX_WR - * @return New value for ptr, to be used in the next call - */ -// FIXME Update documentation - void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); - - /** - * @brief This function is being called by recv() also. - * - * This function read the Rx read pointer register - * and after copy the data from receive buffer update the Rx write pointer register. - * User should read upper byte first and lower byte later to get proper value. - */ - void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); - - inline void setGatewayIp(uint8_t *_addr); - inline void getGatewayIp(uint8_t *_addr); - - inline void setSubnetMask(uint8_t *_addr); - inline void getSubnetMask(uint8_t *_addr); - - inline void setMACAddress(uint8_t * addr); - inline void getMACAddress(uint8_t * addr); - - inline void setIPAddress(uint8_t * addr); - inline void getIPAddress(uint8_t * addr); - - inline void setRetransmissionTime(uint16_t timeout); - inline void setRetransmissionCount(uint8_t _retry); - - void execCmdSn(SOCKET s, SockCMD _cmd); - - uint16_t getTXFreeSize(SOCKET s); - uint16_t getRXReceivedSize(SOCKET s); - - - // W5100 Registers - // --------------- -private: - static uint8_t write(uint16_t _addr, uint8_t _data); - static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); - static uint8_t read(uint16_t addr); - static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); - -#define __GP_REGISTER8(name, address) \ - static inline void write##name(uint8_t _data) { \ - write(address, _data); \ - } \ - static inline uint8_t read##name() { \ - return read(address); \ - } -#define __GP_REGISTER16(name, address) \ - static void write##name(uint16_t _data) { \ - write(address, _data >> 8); \ - write(address+1, _data & 0xFF); \ - } \ - static uint16_t read##name() { \ - uint16_t res = read(address); \ - res = (res << 8) + read(address + 1); \ - return res; \ - } -#define __GP_REGISTER_N(name, address, size) \ - static uint16_t write##name(uint8_t *_buff) { \ - return write(address, _buff, size); \ - } \ - static uint16_t read##name(uint8_t *_buff) { \ - return read(address, _buff, size); \ - } - -public: - __GP_REGISTER8 (MR, 0x0000); // Mode - __GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address - __GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address - __GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address - __GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address - __GP_REGISTER8 (IR, 0x0015); // Interrupt - __GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask - __GP_REGISTER16(RTR, 0x0017); // Timeout address - __GP_REGISTER8 (RCR, 0x0019); // Retry count - __GP_REGISTER8 (RMSR, 0x001A); // Receive memory size - __GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size - __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode - __GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer - __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number - __GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode - __GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode - -#undef __GP_REGISTER8 -#undef __GP_REGISTER16 -#undef __GP_REGISTER_N - - // W5100 Socket registers - // ---------------------- -private: - static inline uint8_t readSn(SOCKET _s, uint16_t _addr); - static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); - static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); - static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); - - static const uint16_t CH_BASE = 0x0400; - static const uint16_t CH_SIZE = 0x0100; - -#define __SOCKET_REGISTER8(name, address) \ - static inline void write##name(SOCKET _s, uint8_t _data) { \ - writeSn(_s, address, _data); \ - } \ - static inline uint8_t read##name(SOCKET _s) { \ - return readSn(_s, address); \ - } -#define __SOCKET_REGISTER16(name, address) \ - static void write##name(SOCKET _s, uint16_t _data) { \ - writeSn(_s, address, _data >> 8); \ - writeSn(_s, address+1, _data & 0xFF); \ - } \ - static uint16_t read##name(SOCKET _s) { \ - uint16_t res = readSn(_s, address); \ - uint16_t res2 = readSn(_s,address + 1); \ - res = res << 8; \ - res2 = res2 & 0xFF; \ - res = res | res2; \ - return res; \ - } -#define __SOCKET_REGISTER_N(name, address, size) \ - static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \ - return writeSn(_s, address, _buff, size); \ - } \ - static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \ - return readSn(_s, address, _buff, size); \ - } - -public: - __SOCKET_REGISTER8(SnMR, 0x0000) // Mode - __SOCKET_REGISTER8(SnCR, 0x0001) // Command - __SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt - __SOCKET_REGISTER8(SnSR, 0x0003) // Status - __SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port - __SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr - __SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr - __SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port - __SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size - __SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode - __SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS - __SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL - __SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size - __SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer - __SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer - __SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size - __SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer - __SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?) - -#undef __SOCKET_REGISTER8 -#undef __SOCKET_REGISTER16 -#undef __SOCKET_REGISTER_N - - -private: - static const uint8_t RST = 7; // Reset BIT - - static const int SOCKETS = 4; - static const uint16_t SMASK = 0x07FF; // Tx buffer MASK - static const uint16_t RMASK = 0x07FF; // Rx buffer MASK -public: - static const uint16_t SSIZE = 2048; // Max Tx buffer size -private: - static const uint16_t RSIZE = 2048; // Max Rx buffer size - uint16_t SBASE[SOCKETS]; // Tx buffer base address - uint16_t RBASE[SOCKETS]; // Rx buffer base address - -private: -#if defined(ARDUINO_ARCH_AVR) -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - inline static void initSS() { DDRB |= _BV(4); }; - inline static void setSS() { PORTB &= ~_BV(4); }; - inline static void resetSS() { PORTB |= _BV(4); }; -#elif defined(__AVR_ATmega32U4__) - inline static void initSS() { DDRB |= _BV(6); }; - inline static void setSS() { PORTB &= ~_BV(6); }; - inline static void resetSS() { PORTB |= _BV(6); }; -#elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__) - inline static void initSS() { DDRB |= _BV(0); }; - inline static void setSS() { PORTB &= ~_BV(0); }; - inline static void resetSS() { PORTB |= _BV(0); }; -#else - inline static void initSS() { DDRB |= _BV(2); }; - inline static void setSS() { PORTB &= ~_BV(2); }; - inline static void resetSS() { PORTB |= _BV(2); }; -#endif -#endif // ARDUINO_ARCH_AVR - -#if defined(__ARDUINO_ARC__) - inline static void initSS() { pinMode(10, OUTPUT); }; - inline static void setSS() { digitalWrite(10, LOW); }; - inline static void resetSS() { digitalWrite(10, HIGH); }; -#endif -}; - -extern W5100Class W5100; - -uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) { - return read(CH_BASE + _s * CH_SIZE + _addr); -} - -uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { - return write(CH_BASE + _s * CH_SIZE + _addr, _data); -} - -uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { - return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); -} - -uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { - return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); -} - -void W5100Class::getGatewayIp(uint8_t *_addr) { - readGAR(_addr); -} - -void W5100Class::setGatewayIp(uint8_t *_addr) { - writeGAR(_addr); -} - -void W5100Class::getSubnetMask(uint8_t *_addr) { - readSUBR(_addr); -} - -void W5100Class::setSubnetMask(uint8_t *_addr) { - writeSUBR(_addr); -} - -void W5100Class::getMACAddress(uint8_t *_addr) { - readSHAR(_addr); -} - -void W5100Class::setMACAddress(uint8_t *_addr) { - writeSHAR(_addr); -} - -void W5100Class::getIPAddress(uint8_t *_addr) { - readSIPR(_addr); -} - -void W5100Class::setIPAddress(uint8_t *_addr) { - writeSIPR(_addr); -} - -void W5100Class::setRetransmissionTime(uint16_t _timeout) { - writeRTR(_timeout); -} - -void W5100Class::setRetransmissionCount(uint8_t _retry) { - writeRCR(_retry); -} - -#endif diff --git a/libraries/SD/README.adoc b/libraries/SD/README.adoc deleted file mode 100644 index fabff563..00000000 --- a/libraries/SD/README.adoc +++ /dev/null @@ -1,24 +0,0 @@ -= SD Library for Arduino = - -The SD library allows for reading from and writing to SD cards. - -For more information about this library please visit us at -http://www.arduino.cc/en/Reference/SD - -== License == - - Copyright (C) 2009 by William Greiman -Copyright (c) 2010 SparkFun Electronics - -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 . diff --git a/libraries/SD/examples/CardInfo/CardInfo.ino b/libraries/SD/examples/CardInfo/CardInfo.ino deleted file mode 100644 index a365de26..00000000 --- a/libraries/SD/examples/CardInfo/CardInfo.ino +++ /dev/null @@ -1,111 +0,0 @@ -/* - SD card test - - This example shows how use the utility libraries on which the' - SD library is based in order to get info about your SD card. - Very useful for testing a card when you're not sure whether its working or not. - - The circuit: - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila - ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila - ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila - ** CS - depends on your SD card shield or module. - Pin 4 used here for consistency with other Arduino examples - - - created 28 Mar 2011 - by Limor Fried - modified 9 Apr 2012 - by Tom Igoe - */ -// include the SD library: -#include -#include - -// set up variables using the SD utility library functions: -Sd2Card card; -SdVolume volume; -SdFile root; - -// change this to match your SD shield or module; -// Arduino Ethernet shield: pin 4 -// Adafruit SD shields and modules: pin 10 -// Sparkfun SD shield: pin 8 -const int chipSelect = 4; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - - Serial.print("\nInitializing SD card..."); - - // we'll use the initialization code from the utility libraries - // since we're just testing if the card is working! - if (!card.init(SPI_HALF_SPEED, chipSelect)) { - Serial.println("initialization failed. Things to check:"); - Serial.println("* is a card inserted?"); - Serial.println("* is your wiring correct?"); - Serial.println("* did you change the chipSelect pin to match your shield or module?"); - return; - } else { - Serial.println("Wiring is correct and a card is present."); - } - - // print the type of card - Serial.print("\nCard type: "); - switch (card.type()) { - case SD_CARD_TYPE_SD1: - Serial.println("SD1"); - break; - case SD_CARD_TYPE_SD2: - Serial.println("SD2"); - break; - case SD_CARD_TYPE_SDHC: - Serial.println("SDHC"); - break; - default: - Serial.println("Unknown"); - } - - // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 - if (!volume.init(card)) { - Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); - return; - } - - - // print the type and size of the first FAT-type volume - uint32_t volumesize; - Serial.print("\nVolume type is FAT"); - Serial.println(volume.fatType(), DEC); - Serial.println(); - - volumesize = volume.blocksPerCluster(); // clusters are collections of blocks - volumesize *= volume.clusterCount(); // we'll have a lot of clusters - volumesize *= 512; // SD card blocks are always 512 bytes - Serial.print("Volume size (bytes): "); - Serial.println(volumesize); - Serial.print("Volume size (Kbytes): "); - volumesize /= 1024; - Serial.println(volumesize); - Serial.print("Volume size (Mbytes): "); - volumesize /= 1024; - Serial.println(volumesize); - - - Serial.println("\nFiles found on the card (name, date and size in bytes): "); - root.openRoot(volume); - - // list all files in the card with date and size - root.ls(LS_R | LS_DATE | LS_SIZE); -} - - -void loop(void) { - -} diff --git a/libraries/SD/examples/Datalogger/Datalogger.ino b/libraries/SD/examples/Datalogger/Datalogger.ino deleted file mode 100644 index 1caccef5..00000000 --- a/libraries/SD/examples/Datalogger/Datalogger.ino +++ /dev/null @@ -1,84 +0,0 @@ -/* - SD card datalogger - - This example shows how to log data from three analog sensors - to an SD card using the SD library. - - The circuit: - * analog sensors on analog ins 0, 1, and 2 - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 - ** MISO - pin 12 - ** CLK - pin 13 - ** CS - pin 4 - - created 24 Nov 2010 - modified 9 Apr 2012 - by Tom Igoe - - This example code is in the public domain. - - */ - -#include -#include - -const int chipSelect = 4; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - - Serial.print("Initializing SD card..."); - - // see if the card is present and can be initialized: - if (!SD.begin(chipSelect)) { - Serial.println("Card failed, or not present"); - // don't do anything more: - return; - } - Serial.println("card initialized."); -} - -void loop() { - // make a string for assembling the data to log: - String dataString = ""; - - // read three sensors and append to the string: - for (int analogPin = 0; analogPin < 3; analogPin++) { - int sensor = analogRead(analogPin); - dataString += String(sensor); - if (analogPin < 2) { - dataString += ","; - } - } - - // open the file. note that only one file can be open at a time, - // so you have to close this one before opening another. - File dataFile = SD.open("datalog.txt", FILE_WRITE); - - // if the file is available, write to it: - if (dataFile) { - dataFile.println(dataString); - dataFile.close(); - // print to the serial port too: - Serial.println(dataString); - } - // if the file isn't open, pop up an error: - else { - Serial.println("error opening datalog.txt"); - } -} - - - - - - - - - diff --git a/libraries/SD/examples/DumpFile/DumpFile.ino b/libraries/SD/examples/DumpFile/DumpFile.ino deleted file mode 100644 index 52f8ba09..00000000 --- a/libraries/SD/examples/DumpFile/DumpFile.ino +++ /dev/null @@ -1,65 +0,0 @@ -/* - SD card file dump - - This example shows how to read a file from the SD card using the - SD library and send it over the serial port. - - The circuit: - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 - ** MISO - pin 12 - ** CLK - pin 13 - ** CS - pin 4 - - created 22 December 2010 - by Limor Fried - modified 9 Apr 2012 - by Tom Igoe - - This example code is in the public domain. - - */ - -#include -#include - -const int chipSelect = 4; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - - Serial.print("Initializing SD card..."); - - // see if the card is present and can be initialized: - if (!SD.begin(chipSelect)) { - Serial.println("Card failed, or not present"); - // don't do anything more: - return; - } - Serial.println("card initialized."); - - // open the file. note that only one file can be open at a time, - // so you have to close this one before opening another. - File dataFile = SD.open("datalog.txt"); - - // if the file is available, write to it: - if (dataFile) { - while (dataFile.available()) { - Serial.write(dataFile.read()); - } - dataFile.close(); - } - // if the file isn't open, pop up an error: - else { - Serial.println("error opening datalog.txt"); - } -} - -void loop() { -} - diff --git a/libraries/SD/examples/Files/Files.ino b/libraries/SD/examples/Files/Files.ino deleted file mode 100644 index ca0f8f17..00000000 --- a/libraries/SD/examples/Files/Files.ino +++ /dev/null @@ -1,75 +0,0 @@ -/* - SD card basic file example - - This example shows how to create and destroy an SD card file - The circuit: - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 - ** MISO - pin 12 - ** CLK - pin 13 - ** CS - pin 4 - - created Nov 2010 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - - This example code is in the public domain. - - */ -#include -#include - -File myFile; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - - Serial.print("Initializing SD card..."); - - if (!SD.begin(4)) { - Serial.println("initialization failed!"); - return; - } - Serial.println("initialization done."); - - if (SD.exists("example.txt")) { - Serial.println("example.txt exists."); - } else { - Serial.println("example.txt doesn't exist."); - } - - // open a new file and immediately close it: - Serial.println("Creating example.txt..."); - myFile = SD.open("example.txt", FILE_WRITE); - myFile.close(); - - // Check to see if the file exists: - if (SD.exists("example.txt")) { - Serial.println("example.txt exists."); - } else { - Serial.println("example.txt doesn't exist."); - } - - // delete the file: - Serial.println("Removing example.txt..."); - SD.remove("example.txt"); - - if (SD.exists("example.txt")) { - Serial.println("example.txt exists."); - } else { - Serial.println("example.txt doesn't exist."); - } -} - -void loop() { - // nothing happens after setup finishes. -} - - - diff --git a/libraries/SD/examples/ReadWrite/ReadWrite.ino b/libraries/SD/examples/ReadWrite/ReadWrite.ino deleted file mode 100644 index 7d9e9d98..00000000 --- a/libraries/SD/examples/ReadWrite/ReadWrite.ino +++ /dev/null @@ -1,79 +0,0 @@ -/* - SD card read/write - - This example shows how to read and write data to and from an SD card file - The circuit: - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 - ** MISO - pin 12 - ** CLK - pin 13 - ** CS - pin 4 - - created Nov 2010 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - - This example code is in the public domain. - - */ - -#include -#include - -File myFile; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - - Serial.print("Initializing SD card..."); - - if (!SD.begin(4)) { - Serial.println("initialization failed!"); - return; - } - Serial.println("initialization done."); - - // open the file. note that only one file can be open at a time, - // so you have to close this one before opening another. - myFile = SD.open("test.txt", FILE_WRITE); - - // if the file opened okay, write to it: - if (myFile) { - Serial.print("Writing to test.txt..."); - myFile.println("testing 1, 2, 3."); - // close the file: - myFile.close(); - Serial.println("done."); - } else { - // if the file didn't open, print an error: - Serial.println("error opening test.txt"); - } - - // re-open the file for reading: - myFile = SD.open("test.txt"); - if (myFile) { - Serial.println("test.txt:"); - - // read from the file until there's nothing else in it: - while (myFile.available()) { - Serial.write(myFile.read()); - } - // close the file: - myFile.close(); - } else { - // if the file didn't open, print an error: - Serial.println("error opening test.txt"); - } -} - -void loop() { - // nothing happens after setup -} - - diff --git a/libraries/SD/examples/listfiles/listfiles.ino b/libraries/SD/examples/listfiles/listfiles.ino deleted file mode 100644 index 75297f51..00000000 --- a/libraries/SD/examples/listfiles/listfiles.ino +++ /dev/null @@ -1,80 +0,0 @@ -/* - Listfiles - - This example shows how print out the files in a - directory on a SD card - - The circuit: - * SD card attached to SPI bus as follows: - ** MOSI - pin 11 - ** MISO - pin 12 - ** CLK - pin 13 - ** CS - pin 4 - - created Nov 2010 - by David A. Mellis - modified 9 Apr 2012 - by Tom Igoe - modified 2 Feb 2014 - by Scott Fitzgerald - - This example code is in the public domain. - - */ -#include -#include - -File root; - -void setup() { - // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - Serial.print("Initializing SD card..."); - - if (!SD.begin(4)) { - Serial.println("initialization failed!"); - return; - } - Serial.println("initialization done."); - - root = SD.open("/"); - - printDirectory(root, 0); - - Serial.println("done!"); -} - -void loop() { - // nothing happens after setup finishes. -} - -void printDirectory(File dir, int numTabs) { - while (true) { - - File entry = dir.openNextFile(); - if (! entry) { - // no more files - break; - } - for (uint8_t i = 0; i < numTabs; i++) { - Serial.print('\t'); - } - Serial.print(entry.name()); - if (entry.isDirectory()) { - Serial.println("/"); - printDirectory(entry, numTabs + 1); - } else { - // files have sizes, directories do not - Serial.print("\t\t"); - Serial.println(entry.size(), DEC); - } - entry.close(); - } -} - - - diff --git a/libraries/SD/keywords.txt b/libraries/SD/keywords.txt deleted file mode 100644 index 91e74b83..00000000 --- a/libraries/SD/keywords.txt +++ /dev/null @@ -1,31 +0,0 @@ -####################################### -# Syntax Coloring Map SD -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -SD KEYWORD1 SD -File KEYWORD1 SD -SDFile KEYWORD1 SD - -####################################### -# Methods and Functions (KEYWORD2) -####################################### -begin KEYWORD2 -exists KEYWORD2 -mkdir KEYWORD2 -remove KEYWORD2 -rmdir KEYWORD2 -open KEYWORD2 -close KEYWORD2 -seek KEYWORD2 -position KEYWORD2 -size KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### -FILE_READ LITERAL1 -FILE_WRITE LITERAL1 diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties deleted file mode 100644 index 0bb170cb..00000000 --- a/libraries/SD/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=SD -version=1.0.6 -author=Arduino, SparkFun -maintainer=Arduino -sentence=Enables reading and writing on SD cards. For all boards. -paragraph=Once an SD memory card is connected to the SPI interface of the board you can create files and read/write on them. You can also move through directories on the SD card. -category=Data Storage -url=http://www.arduino.cc/en/Reference/SD -architectures=arc32 diff --git a/libraries/SD/src/File.cpp b/libraries/SD/src/File.cpp deleted file mode 100644 index 6eee39aa..00000000 --- a/libraries/SD/src/File.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - - SD - a slightly more friendly wrapper for sdfatlib - - This library aims to expose a subset of SD card functionality - in the form of a higher level "wrapper" object. - - License: GNU General Public License V3 - (Because sdfatlib is licensed with this.) - - (C) Copyright 2010 SparkFun Electronics - - */ - -#include - -/* for debugging file open/close leaks - uint8_t nfilecount=0; -*/ - -File::File(SdFile f, const char *n) { - // oh man you are kidding me, new() doesnt exist? Ok we do it by hand! - _file = (SdFile *)malloc(sizeof(SdFile)); - if (_file) { - memcpy(_file, &f, sizeof(SdFile)); - - strncpy(_name, n, 12); - _name[12] = 0; - - /* for debugging file open/close leaks - nfilecount++; - Serial.print("Created \""); - Serial.print(n); - Serial.print("\": "); - Serial.println(nfilecount, DEC); - */ - } -} - -File::File(void) { - _file = 0; - _name[0] = 0; - //Serial.print("Created empty file object"); -} - -// returns a pointer to the file name -char *File::name(void) { - return _name; -} - -// a directory is a special type of file -boolean File::isDirectory(void) { - return (_file && _file->isDir()); -} - - -size_t File::write(uint8_t val) { - return write(&val, 1); -} - -size_t File::write(const uint8_t *buf, size_t size) { - size_t t; - if (!_file) { - setWriteError(); - return 0; - } - _file->clearWriteError(); - t = _file->write(buf, size); - if (_file->getWriteError()) { - setWriteError(); - return 0; - } - return t; -} - -int File::peek() { - if (! _file) - return 0; - - int c = _file->read(); - if (c != -1) _file->seekCur(-1); - return c; -} - -int File::read() { - if (_file) - return _file->read(); - return -1; -} - -// buffered read for more efficient, high speed reading -int File::read(void *buf, uint16_t nbyte) { - if (_file) - return _file->read(buf, nbyte); - return 0; -} - -int File::available() { - if (! _file) return 0; - - uint32_t n = size() - position(); - - return n > 0X7FFF ? 0X7FFF : n; -} - -void File::flush() { - if (_file) - _file->sync(); -} - -boolean File::seek(uint32_t pos) { - if (! _file) return false; - - return _file->seekSet(pos); -} - -uint32_t File::position() { - if (! _file) return -1; - return _file->curPosition(); -} - -uint32_t File::size() { - if (! _file) return 0; - return _file->fileSize(); -} - -void File::close() { - if (_file) { - _file->close(); - free(_file); - _file = 0; - - /* for debugging file open/close leaks - nfilecount--; - Serial.print("Deleted "); - Serial.println(nfilecount, DEC); - */ - } -} - -File::operator bool() { - if (_file) - return _file->isOpen(); - return false; -} - diff --git a/libraries/SD/src/README.txt b/libraries/SD/src/README.txt deleted file mode 100644 index 495ea4c7..00000000 --- a/libraries/SD/src/README.txt +++ /dev/null @@ -1,13 +0,0 @@ - -** SD - a slightly more friendly wrapper for sdfatlib ** - -This library aims to expose a subset of SD card functionality in the -form of a higher level "wrapper" object. - -License: GNU General Public License V3 - (Because sdfatlib is licensed with this.) - -(C) Copyright 2010 SparkFun Electronics - -Now better than ever with optimization, multiple file support, directory handling, etc - ladyada! - diff --git a/libraries/SD/src/SD.cpp b/libraries/SD/src/SD.cpp deleted file mode 100644 index 2afb9d9a..00000000 --- a/libraries/SD/src/SD.cpp +++ /dev/null @@ -1,620 +0,0 @@ -/* - - SD - a slightly more friendly wrapper for sdfatlib - - This library aims to expose a subset of SD card functionality - in the form of a higher level "wrapper" object. - - License: GNU General Public License V3 - (Because sdfatlib is licensed with this.) - - (C) Copyright 2010 SparkFun Electronics - - - This library provides four key benefits: - - * Including `SD.h` automatically creates a global - `SD` object which can be interacted with in a similar - manner to other standard global objects like `Serial` and `Ethernet`. - - * Boilerplate initialisation code is contained in one method named - `begin` and no further objects need to be created in order to access - the SD card. - - * Calls to `open` can supply a full path name including parent - directories which simplifies interacting with files in subdirectories. - - * Utility methods are provided to determine whether a file exists - and to create a directory heirarchy. - - - Note however that not all functionality provided by the underlying - sdfatlib library is exposed. - - */ - -/* - - Implementation Notes - - In order to handle multi-directory path traversal, functionality that - requires this ability is implemented as callback functions. - - Individual methods call the `walkPath` function which performs the actual - directory traversal (swapping between two different directory/file handles - along the way) and at each level calls the supplied callback function. - - Some types of functionality will take an action at each level (e.g. exists - or make directory) which others will only take an action at the bottom - level (e.g. open). - - */ - -#include "SD.h" - -namespace SDLib { - -// Used by `getNextPathComponent` -#define MAX_COMPONENT_LEN 12 // What is max length? -#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1 - -bool getNextPathComponent(const char *path, unsigned int *p_offset, - char *buffer) { - /* - - Parse individual path components from a path. - - e.g. after repeated calls '/foo/bar/baz' will be split - into 'foo', 'bar', 'baz'. - - This is similar to `strtok()` but copies the component into the - supplied buffer rather than modifying the original string. - - - `buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size. - - `p_offset` needs to point to an integer of the offset at - which the previous path component finished. - - Returns `true` if more components remain. - - Returns `false` if this is the last component. - (This means path ended with 'foo' or 'foo/'.) - - */ - - // TODO: Have buffer local to this function, so we know it's the - // correct length? - - int bufferOffset = 0; - - int offset = *p_offset; - - // Skip root or other separator - if (path[offset] == '/') { - offset++; - } - - // Copy the next next path segment - while (bufferOffset < MAX_COMPONENT_LEN - && (path[offset] != '/') - && (path[offset] != '\0')) { - buffer[bufferOffset++] = path[offset++]; - } - - buffer[bufferOffset] = '\0'; - - // Skip trailing separator so we can determine if this - // is the last component in the path or not. - if (path[offset] == '/') { - offset++; - } - - *p_offset = offset; - - return (path[offset] != '\0'); -} - - - -boolean walkPath(const char *filepath, SdFile& parentDir, - boolean (*callback)(SdFile& parentDir, - const char *filePathComponent, - boolean isLastComponent, - void *object), - void *object = NULL) { - /* - - When given a file path (and parent directory--normally root), - this function traverses the directories in the path and at each - level calls the supplied callback function while also providing - the supplied object for context if required. - - e.g. given the path '/foo/bar/baz' - the callback would be called at the equivalent of - '/foo', '/foo/bar' and '/foo/bar/baz'. - - The implementation swaps between two different directory/file - handles as it traverses the directories and does not use recursion - in an attempt to use memory efficiently. - - If a callback wishes to stop the directory traversal it should - return false--in this case the function will stop the traversal, - tidy up and return false. - - If a directory path doesn't exist at some point this function will - also return false and not subsequently call the callback. - - If a directory path specified is complete, valid and the callback - did not indicate the traversal should be interrupted then this - function will return true. - - */ - - - SdFile subfile1; - SdFile subfile2; - - char buffer[PATH_COMPONENT_BUFFER_LEN]; - - unsigned int offset = 0; - - SdFile *p_parent; - SdFile *p_child; - - SdFile *p_tmp_sdfile; - - p_child = &subfile1; - - p_parent = &parentDir; - - while (true) { - - boolean moreComponents = getNextPathComponent(filepath, &offset, buffer); - - boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object); - - if (!shouldContinue) { - // TODO: Don't repeat this code? - // If it's one we've created then we - // don't need the parent handle anymore. - if (p_parent != &parentDir) { - (*p_parent).close(); - } - return false; - } - - if (!moreComponents) { - break; - } - - boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY); - - // If it's one we've created then we - // don't need the parent handle anymore. - if (p_parent != &parentDir) { - (*p_parent).close(); - } - - // Handle case when it doesn't exist and we can't continue... - if (exists) { - // We alternate between two file handles as we go down - // the path. - if (p_parent == &parentDir) { - p_parent = &subfile2; - } - - p_tmp_sdfile = p_parent; - p_parent = p_child; - p_child = p_tmp_sdfile; - } else { - return false; - } - } - - if (p_parent != &parentDir) { - (*p_parent).close(); // TODO: Return/ handle different? - } - - return true; -} - - - -/* - - The callbacks used to implement various functionality follow. - - Each callback is supplied with a parent directory handle, - character string with the name of the current file path component, - a flag indicating if this component is the last in the path and - a pointer to an arbitrary object used for context. - - */ - -boolean callback_pathExists(SdFile& parentDir, const char *filePathComponent, - boolean isLastComponent, void *object) { - /* - - Callback used to determine if a file/directory exists in parent - directory. - - Returns true if file path exists. - - */ - SdFile child; - - boolean exists = child.open(parentDir, filePathComponent, O_RDONLY); - - if (exists) { - child.close(); - } - - return exists; -} - - - -boolean callback_makeDirPath(SdFile& parentDir, const char *filePathComponent, - boolean isLastComponent, void *object) { - /* - - Callback used to create a directory in the parent directory if - it does not already exist. - - Returns true if a directory was created or it already existed. - - */ - boolean result = false; - SdFile child; - - result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object); - if (!result) { - result = child.makeDir(parentDir, filePathComponent); - } - - return result; -} - - - /* - -boolean callback_openPath(SdFile& parentDir, char *filePathComponent, - boolean isLastComponent, void *object) { - - Callback used to open a file specified by a filepath that may - specify one or more directories above it. - - Expects the context object to be an instance of `SDClass` and - will use the `file` property of the instance to open the requested - file/directory with the associated file open mode property. - - Always returns true if the directory traversal hasn't reached the - bottom of the directory heirarchy. - - Returns false once the file has been opened--to prevent the traversal - from descending further. (This may be unnecessary.) - - if (isLastComponent) { - SDClass *p_SD = static_cast(object); - p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode); - if (p_SD->fileOpenMode == FILE_WRITE) { - p_SD->file.seekSet(p_SD->file.fileSize()); - } - // TODO: Return file open result? - return false; - } - return true; -} - */ - - - -boolean callback_remove(SdFile& parentDir, const char *filePathComponent, - boolean isLastComponent, void *object) { - if (isLastComponent) { - return SdFile::remove(parentDir, filePathComponent); - } - return true; -} - -boolean callback_rmdir(SdFile& parentDir, const char *filePathComponent, - boolean isLastComponent, void *object) { - if (isLastComponent) { - SdFile f; - if (!f.open(parentDir, filePathComponent, O_READ)) return false; - return f.rmDir(); - } - return true; -} - - - -/* Implementation of class used to create `SDCard` object. */ - - - -boolean SDClass::begin(uint8_t csPin) { - /* - - Performs the initialisation required by the sdfatlib library. - - Return true if initialization succeeds, false otherwise. - - */ - return card.init(SPI_HALF_SPEED, csPin) && - volume.init(card) && - root.openRoot(volume); -} - - - -// this little helper is used to traverse paths -SdFile SDClass::getParentDir(const char *filepath, int *index) { - // get parent directory - SdFile d1 = root; // start with the mostparent, root! - SdFile d2; - - // we'll use the pointers to swap between the two objects - SdFile *parent = &d1; - SdFile *subdir = &d2; - - const char *origpath = filepath; - - while (strchr(filepath, '/')) { - - // get rid of leading /'s - if (filepath[0] == '/') { - filepath++; - continue; - } - - if (! strchr(filepath, '/')) { - // it was in the root directory, so leave now - break; - } - - // extract just the name of the next subdirectory - uint8_t idx = strchr(filepath, '/') - filepath; - if (idx > 12) - idx = 12; // dont let them specify long names - char subdirname[13]; - strncpy(subdirname, filepath, idx); - subdirname[idx] = 0; - - // close the subdir (we reuse them) if open - subdir->close(); - if (! subdir->open(parent, subdirname, O_READ)) { - // failed to open one of the subdirectories - return SdFile(); - } - // move forward to the next subdirectory - filepath += idx; - - // we reuse the objects, close it. - parent->close(); - - // swap the pointers - SdFile *t = parent; - parent = subdir; - subdir = t; - } - - *index = (int)(filepath - origpath); - // parent is now the parent diretory of the file! - return *parent; -} - - -File SDClass::open(const char *filepath, uint8_t mode) { - /* - - Open the supplied file path for reading or writing. - - The file content can be accessed via the `file` property of - the `SDClass` object--this property is currently - a standard `SdFile` object from `sdfatlib`. - - Defaults to read only. - - If `write` is true, default action (when `append` is true) is to - append data to the end of the file. - - If `append` is false then the file will be truncated first. - - If the file does not exist and it is opened for writing the file - will be created. - - An attempt to open a file for reading that does not exist is an - error. - - */ - - int pathidx; - - // do the interative search - SdFile parentdir = getParentDir(filepath, &pathidx); - // no more subdirs! - - filepath += pathidx; - - if (! filepath[0]) { - // it was the directory itself! - return File(parentdir, "/"); - } - - // Open the file itself - SdFile file; - - // failed to open a subdir! - if (!parentdir.isOpen()) - return File(); - - // there is a special case for the Root directory since its a static dir - if (parentdir.isRoot()) { - if ( ! file.open(root, filepath, mode)) { - // failed to open the file :( - return File(); - } - // dont close the root! - } else { - if ( ! file.open(parentdir, filepath, mode)) { - return File(); - } - // close the parent - parentdir.close(); - } - - if (mode & (O_APPEND | O_WRITE)) - file.seekSet(file.fileSize()); - return File(file, filepath); -} - - -/* -File SDClass::open(char *filepath, uint8_t mode) { - // - - Open the supplied file path for reading or writing. - - The file content can be accessed via the `file` property of - the `SDClass` object--this property is currently - a standard `SdFile` object from `sdfatlib`. - - Defaults to read only. - - If `write` is true, default action (when `append` is true) is to - append data to the end of the file. - - If `append` is false then the file will be truncated first. - - If the file does not exist and it is opened for writing the file - will be created. - - An attempt to open a file for reading that does not exist is an - error. - - // - - // TODO: Allow for read&write? (Possibly not, as it requires seek.) - - fileOpenMode = mode; - walkPath(filepath, root, callback_openPath, this); - - return File(); - -} -*/ - - -//boolean SDClass::close() { -// /* -// -// Closes the file opened by the `open` method. -// -// */ -// file.close(); -//} - - -boolean SDClass::exists(const char *filepath) { - /* - - Returns true if the supplied file path exists. - - */ - return walkPath(filepath, root, callback_pathExists); -} - - -//boolean SDClass::exists(char *filepath, SdFile& parentDir) { -// /* -// -// Returns true if the supplied file path rooted at `parentDir` -// exists. -// -// */ -// return walkPath(filepath, parentDir, callback_pathExists); -//} - - -boolean SDClass::mkdir(const char *filepath) { - /* - - Makes a single directory or a heirarchy of directories. - - A rough equivalent to `mkdir -p`. - - */ - return walkPath(filepath, root, callback_makeDirPath); -} - -boolean SDClass::rmdir(const char *filepath) { - /* - - Remove a single directory or a heirarchy of directories. - - A rough equivalent to `rm -rf`. - - */ - return walkPath(filepath, root, callback_rmdir); -} - -boolean SDClass::remove(const char *filepath) { - return walkPath(filepath, root, callback_remove); -} - - -// allows you to recurse into a directory -File File::openNextFile(uint8_t mode) { - dir_t p; - - //Serial.print("\t\treading dir..."); - while (_file->readDir(&p) > 0) { - - // done if past last used entry - if (p.name[0] == DIR_NAME_FREE) { - //Serial.println("end"); - return File(); - } - - // skip deleted entry and entries for . and .. - if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') { - //Serial.println("dots"); - continue; - } - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(&p)) { - //Serial.println("notafile"); - continue; - } - - // print file name with possible blank fill - SdFile f; - char name[13]; - _file->dirName(p, name); - //Serial.print("try to open file "); - //Serial.println(name); - - if (f.open(_file, name, mode)) { - //Serial.println("OK!"); - return File(f, name); - } else { - //Serial.println("ugh"); - return File(); - } - } - - //Serial.println("nothing"); - return File(); -} - -void File::rewindDirectory(void) { - if (isDirectory()) - _file->rewind(); -} - -SDClass SD; - -}; diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h deleted file mode 100644 index 0435c38b..00000000 --- a/libraries/SD/src/SD.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - - SD - a slightly more friendly wrapper for sdfatlib - - This library aims to expose a subset of SD card functionality - in the form of a higher level "wrapper" object. - - License: GNU General Public License V3 - (Because sdfatlib is licensed with this.) - - (C) Copyright 2010 SparkFun Electronics - - */ - -#ifndef __SD_H__ -#define __SD_H__ - -#include - -#include -#include - -#define FILE_READ O_READ -#define FILE_WRITE (O_READ | O_WRITE | O_CREAT) - -namespace SDLib { - -class File : public Stream { - private: - char _name[13]; // our name - SdFile *_file; // underlying file pointer - -public: - File(SdFile f, const char *name); // wraps an underlying SdFile - File(void); // 'empty' constructor - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *buf, size_t size); - virtual int read(); - virtual int peek(); - virtual int available(); - virtual void flush(); - int read(void *buf, uint16_t nbyte); - boolean seek(uint32_t pos); - uint32_t position(); - uint32_t size(); - void close(); - operator bool(); - char * name(); - - boolean isDirectory(void); - File openNextFile(uint8_t mode = O_RDONLY); - void rewindDirectory(void); - - using Print::write; -}; - -class SDClass { - -private: - // These are required for initialisation and use of sdfatlib - Sd2Card card; - SdVolume volume; - SdFile root; - - // my quick&dirty iterator, should be replaced - SdFile getParentDir(const char *filepath, int *indx); -public: - // This needs to be called to set up the connection to the SD card - // before other methods are used. - boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN); - - // Open the specified file/directory with the supplied mode (e.g. read or - // write, etc). Returns a File object for interacting with the file. - // Note that currently only one file can be open at a time. - File open(const char *filename, uint8_t mode = FILE_READ); - File open(const String &filename, uint8_t mode = FILE_READ) { return open( filename.c_str(), mode ); } - - // Methods to determine if the requested file path exists. - boolean exists(const char *filepath); - boolean exists(const String &filepath) { return exists(filepath.c_str()); } - - // Create the requested directory heirarchy--if intermediate directories - // do not exist they will be created. - boolean mkdir(const char *filepath); - boolean mkdir(const String &filepath) { return mkdir(filepath.c_str()); } - - // Delete the file. - boolean remove(const char *filepath); - boolean remove(const String &filepath) { return remove(filepath.c_str()); } - - boolean rmdir(const char *filepath); - boolean rmdir(const String &filepath) { return rmdir(filepath.c_str()); } - -private: - - // This is used to determine the mode used to open a file - // it's here because it's the easiest place to pass the - // information through the directory walking function. But - // it's probably not the best place for it. - // It shouldn't be set directly--it is set via the parameters to `open`. - int fileOpenMode; - - friend class File; - friend boolean callback_openPath(SdFile&, const char *, boolean, void *); -}; - -extern SDClass SD; - -}; - -// We enclose File and SD classes in namespace SDLib to avoid conflicts -// with others legacy libraries that redefines File class. - -// This ensure compatibility with sketches that uses only SD library -using namespace SDLib; - -// This allows sketches to use SDLib::File with other libraries (in the -// sketch you must use SDFile instead of File to disambiguate) -typedef SDLib::File SDFile; -typedef SDLib::SDClass SDFileSystemClass; -#define SDFileSystem SDLib::SD - -#endif diff --git a/libraries/SD/src/utility/FatStructs.h b/libraries/SD/src/utility/FatStructs.h deleted file mode 100644 index 32ccd6b8..00000000 --- a/libraries/SD/src/utility/FatStructs.h +++ /dev/null @@ -1,418 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#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; -} __attribute__((packed)); -/** 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; -} __attribute__((packed)); -/** 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]; -} __attribute__((packed)); -/** 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; -} __attribute__((packed)); -//------------------------------------------------------------------------------ -// 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; -} __attribute__((packed)); -//------------------------------------------------------------------------------ -// 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 diff --git a/libraries/SD/src/utility/Sd2Card.cpp b/libraries/SD/src/utility/Sd2Card.cpp deleted file mode 100644 index 94dcd127..00000000 --- a/libraries/SD/src/utility/Sd2Card.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card 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 Sd2Card Library. If not, see - * . - */ -#define USE_SPI_LIB -#include -#include "Sd2Card.h" -//------------------------------------------------------------------------------ -#ifndef SOFTWARE_SPI -#ifdef USE_SPI_LIB -#include -static SPISettings settings; -#endif -// functions for hardware SPI -/** Send a byte to the card */ -static void spiSend(uint8_t b) { -#ifndef USE_SPI_LIB - SPDR = b; - while (!(SPSR & (1 << SPIF))) - ; -#else - SPI.transfer(b); -#endif -} -/** Receive a byte from the card */ -static uint8_t spiRec(void) { -#ifndef USE_SPI_LIB - spiSend(0XFF); - return SPDR; -#else - return SPI.transfer(0xFF); -#endif -} -#else // SOFTWARE_SPI -//------------------------------------------------------------------------------ -/** nop to tune soft SPI timing */ -#define nop asm volatile ("nop\n\t") -//------------------------------------------------------------------------------ -/** Soft SPI receive */ -uint8_t spiRec(void) { - uint8_t data = 0; - // no interrupts during byte receive - about 8 us - cli(); - // output pin high - like sending 0XFF - fastDigitalWrite(SPI_MOSI_PIN, HIGH); - - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, HIGH); - - // adjust so SCK is nice - nop; - nop; - - data <<= 1; - - if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - } - // enable interrupts - sei(); - return data; -} -//------------------------------------------------------------------------------ -/** Soft SPI send */ -void spiSend(uint8_t data) { - // no interrupts during byte send - about 8 us - cli(); - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, LOW); - - fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); - - data <<= 1; - - fastDigitalWrite(SPI_SCK_PIN, HIGH); - } - // hold SCK high for a few ns - nop; - nop; - nop; - nop; - - fastDigitalWrite(SPI_SCK_PIN, LOW); - // enable interrupts - sei(); -} -#endif // SOFTWARE_SPI -//------------------------------------------------------------------------------ -// send command and return error code. Return zero for OK -uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { - // end read if in partialBlockRead mode - readEnd(); - - // select card - chipSelectLow(); - - // wait up to 300 ms if busy - waitNotBusy(300); - - // send command - spiSend(cmd | 0x40); - - // send argument - for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); - - // send CRC - uint8_t crc = 0XFF; - if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 - if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA - spiSend(crc); - - // wait for response - for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) - ; - return status_; -} -//------------------------------------------------------------------------------ -/** - * Determine the size of an SD flash memory card. - * - * \return The number of 512 byte data blocks in the card - * or zero if an error occurs. - */ -uint32_t Sd2Card::cardSize(void) { - csd_t csd; - if (!readCSD(&csd)) return 0; - if (csd.v1.csd_ver == 0) { - uint8_t read_bl_len = csd.v1.read_bl_len; - uint16_t c_size = (csd.v1.c_size_high << 10) - | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; - uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) - | csd.v1.c_size_mult_low; - return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); - } else if (csd.v2.csd_ver == 1) { - uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) - | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; - return (c_size + 1) << 10; - } else { - error(SD_CARD_ERROR_BAD_CSD); - return 0; - } -} -//------------------------------------------------------------------------------ -static uint8_t chip_select_asserted = 0; - -void Sd2Card::chipSelectHigh(void) { - digitalWrite(chipSelectPin_, HIGH); -#ifdef USE_SPI_LIB - if (chip_select_asserted) { - chip_select_asserted = 0; - SPI.endTransaction(); - } -#endif -} -//------------------------------------------------------------------------------ -void Sd2Card::chipSelectLow(void) { -#ifdef USE_SPI_LIB - if (!chip_select_asserted) { - chip_select_asserted = 1; - SPI.beginTransaction(settings); - } -#endif - digitalWrite(chipSelectPin_, LOW); -} -//------------------------------------------------------------------------------ -/** Erase a range of blocks. - * - * \param[in] firstBlock The address of the first block in the range. - * \param[in] lastBlock The address of the last block in the range. - * - * \note This function requests the SD card to do a flash erase for a - * range of blocks. The data on the card after an erase operation is - * either 0 or 1, depends on the card vendor. The card must support - * single block erase. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { - if (!eraseSingleBlockEnable()) { - error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); - goto fail; - } - if (type_ != SD_CARD_TYPE_SDHC) { - firstBlock <<= 9; - lastBlock <<= 9; - } - if (cardCommand(CMD32, firstBlock) - || cardCommand(CMD33, lastBlock) - || cardCommand(CMD38, 0)) { - error(SD_CARD_ERROR_ERASE); - goto fail; - } - if (!waitNotBusy(SD_ERASE_TIMEOUT)) { - error(SD_CARD_ERROR_ERASE_TIMEOUT); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Determine if card supports single block erase. - * - * \return The value one, true, is returned if single block erase is supported. - * The value zero, false, is returned if single block erase is not supported. - */ -uint8_t Sd2Card::eraseSingleBlockEnable(void) { - csd_t csd; - return readCSD(&csd) ? csd.v1.erase_blk_en : 0; -} -//------------------------------------------------------------------------------ -/** - * Initialize an SD flash memory card. - * - * \param[in] sckRateID SPI clock rate selector. See setSckRate(). - * \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. The reason for failure - * can be determined by calling errorCode() and errorData(). - */ -uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { - errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; - chipSelectPin_ = chipSelectPin; - // 16-bit init start time allows over a minute - uint16_t t0 = (uint16_t)millis(); - uint32_t arg; - - // set pin modes - pinMode(chipSelectPin_, OUTPUT); - digitalWrite(chipSelectPin_, HIGH); -#ifndef USE_SPI_LIB - pinMode(SPI_MISO_PIN, INPUT); - pinMode(SPI_MOSI_PIN, OUTPUT); - pinMode(SPI_SCK_PIN, OUTPUT); -#endif - -#ifndef SOFTWARE_SPI -#ifndef USE_SPI_LIB - // SS must be in output mode even it is not chip select - pinMode(SS_PIN, OUTPUT); - digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin - // Enable SPI, Master, clock rate f_osc/128 - SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); - // clear double speed - SPSR &= ~(1 << SPI2X); -#else // USE_SPI_LIB - SPI.begin(); - settings = SPISettings(250000, MSBFIRST, SPI_MODE0); -#endif // USE_SPI_LIB -#endif // SOFTWARE_SPI - - // must supply min of 74 clock cycles with CS high. -#ifdef USE_SPI_LIB - SPI.beginTransaction(settings); -#endif - for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); -#ifdef USE_SPI_LIB - SPI.endTransaction(); -#endif - - chipSelectLow(); - - // command to go idle in SPI mode - while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { - if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_CMD0); - goto fail; - } - } - // check SD version - if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { - type(SD_CARD_TYPE_SD1); - } else { - // only need last byte of r7 response - for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); - if (status_ != 0XAA) { - error(SD_CARD_ERROR_CMD8); - goto fail; - } - type(SD_CARD_TYPE_SD2); - } - // initialize card and send host supports SDHC if SD2 - arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; - - while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { - // check for timeout - if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_ACMD41); - goto fail; - } - } - // if SD2 read OCR register to check for SDHC card - if (type() == SD_CARD_TYPE_SD2) { - if (cardCommand(CMD58, 0)) { - error(SD_CARD_ERROR_CMD58); - goto fail; - } - if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); - // discard rest of ocr - contains allowed voltage range - for (uint8_t i = 0; i < 3; i++) spiRec(); - } - chipSelectHigh(); - -#ifndef SOFTWARE_SPI - return setSckRate(sckRateID); -#else // SOFTWARE_SPI - return true; -#endif // SOFTWARE_SPI - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Enable or disable partial block reads. - * - * Enabling partial block reads improves performance by allowing a block - * to be read over the SPI bus as several sub-blocks. Errors may occur - * if the time between reads is too long since the SD card may timeout. - * The SPI SS line will be held low until the entire block is read or - * readEnd() is called. - * - * Use this for applications like the Adafruit Wave Shield. - * - * \param[in] value The value TRUE (non-zero) or FALSE (zero).) - */ -void Sd2Card::partialBlockRead(uint8_t value) { - readEnd(); - partialBlockRead_ = value; -} -//------------------------------------------------------------------------------ -/** - * Read a 512 byte block from an SD card device. - * - * \param[in] block 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 Sd2Card::readBlock(uint32_t block, uint8_t* dst) { - return readData(block, 0, 512, dst); -} -//------------------------------------------------------------------------------ -/** - * Read part of a 512 byte block from an SD card. - * - * \param[in] block Logical block to be read. - * \param[in] offset Number of bytes to skip at start of block - * \param[out] dst Pointer to the location that will receive the data. - * \param[in] count Number of bytes to read - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::readData(uint32_t block, - uint16_t offset, uint16_t count, uint8_t* dst) { - uint16_t n; - if (count == 0) return true; - if ((count + offset) > 512) { - goto fail; - } - if (!inBlock_ || block != block_ || offset < offset_) { - block_ = block; - // use address if not SDHC card - if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; - if (cardCommand(CMD17, block)) { - error(SD_CARD_ERROR_CMD17); - goto fail; - } - if (!waitStartBlock()) { - goto fail; - } - offset_ = 0; - inBlock_ = 1; - } - -#ifdef OPTIMIZE_HARDWARE_SPI - // start first spi transfer - SPDR = 0XFF; - - // skip data before offset - for (;offset_ < offset; offset_++) { - while (!(SPSR & (1 << SPIF))) - ; - SPDR = 0XFF; - } - // transfer data - n = count - 1; - for (uint16_t i = 0; i < n; i++) { - while (!(SPSR & (1 << SPIF))) - ; - dst[i] = SPDR; - SPDR = 0XFF; - } - // wait for last byte - while (!(SPSR & (1 << SPIF))) - ; - dst[n] = SPDR; - -#else // OPTIMIZE_HARDWARE_SPI - - // skip data before offset - for (;offset_ < offset; offset_++) { - spiRec(); - } - // transfer data - for (uint16_t i = 0; i < count; i++) { - dst[i] = spiRec(); - } -#endif // OPTIMIZE_HARDWARE_SPI - - offset_ += count; - if (!partialBlockRead_ || offset_ >= 512) { - // read rest of data, checksum and set chip select high - readEnd(); - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Skip remaining data in a block when in partial block read mode. */ -void Sd2Card::readEnd(void) { - if (inBlock_) { - // skip data and crc -#ifdef OPTIMIZE_HARDWARE_SPI - // optimize skip for hardware - SPDR = 0XFF; - while (offset_++ < 513) { - while (!(SPSR & (1 << SPIF))) - ; - SPDR = 0XFF; - } - // wait for last crc byte - while (!(SPSR & (1 << SPIF))) - ; -#else // OPTIMIZE_HARDWARE_SPI - while (offset_++ < 514) spiRec(); -#endif // OPTIMIZE_HARDWARE_SPI - chipSelectHigh(); - inBlock_ = 0; - } -} -//------------------------------------------------------------------------------ -/** read CID or CSR register */ -uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { - uint8_t* dst = reinterpret_cast(buf); - if (cardCommand(cmd, 0)) { - error(SD_CARD_ERROR_READ_REG); - goto fail; - } - if (!waitStartBlock()) goto fail; - // transfer data - for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); - spiRec(); // get first crc byte - spiRec(); // get second crc byte - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Set the SPI clock rate. - * - * \param[in] sckRateID A value in the range [0, 6]. - * - * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum - * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 - * for \a scsRateID = 6. - * - * \return The value one, true, is returned for success and the value zero, - * false, is returned for an invalid value of \a sckRateID. - */ -uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { - if (sckRateID > 6) { - error(SD_CARD_ERROR_SCK_RATE); - return false; - } -#ifndef USE_SPI_LIB - // see avr processor datasheet for SPI register bit definitions - if ((sckRateID & 1) || sckRateID == 6) { - SPSR &= ~(1 << SPI2X); - } else { - SPSR |= (1 << SPI2X); - } - SPCR &= ~((1 < SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; - } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** - * Writes a 512 byte block to an SD card. - * - * \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 Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { -#if SD_PROTECT_BLOCK_ZERO - // don't allow write to first block - if (blockNumber == 0) { - error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); - goto fail; - } -#endif // SD_PROTECT_BLOCK_ZERO - - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD24, blockNumber)) { - error(SD_CARD_ERROR_CMD24); - goto fail; - } - if (!writeData(DATA_START_BLOCK, src)) goto fail; - - // wait for flash programming to complete - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_TIMEOUT); - goto fail; - } - // response is r2 so get and check two bytes for nonzero - if (cardCommand(CMD13, 0) || spiRec()) { - error(SD_CARD_ERROR_WRITE_PROGRAMMING); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** Write one data block in a multiple block write sequence */ -uint8_t Sd2Card::writeData(const uint8_t* src) { - // wait for previous write to finish - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_MULTIPLE); - chipSelectHigh(); - return false; - } - return writeData(WRITE_MULTIPLE_TOKEN, src); -} -//------------------------------------------------------------------------------ -// send one block of data for write block or write multiple blocks -uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { -#ifdef OPTIMIZE_HARDWARE_SPI - - // send data - optimized loop - SPDR = token; - - // send two byte per iteration - for (uint16_t i = 0; i < 512; i += 2) { - while (!(SPSR & (1 << SPIF))) - ; - SPDR = src[i]; - while (!(SPSR & (1 << SPIF))) - ; - SPDR = src[i+1]; - } - - // wait for last data byte - while (!(SPSR & (1 << SPIF))) - ; - -#else // OPTIMIZE_HARDWARE_SPI - spiSend(token); - for (uint16_t i = 0; i < 512; i++) { - spiSend(src[i]); - } -#endif // OPTIMIZE_HARDWARE_SPI - spiSend(0xff); // dummy crc - spiSend(0xff); // dummy crc - - status_ = spiRec(); - if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { - error(SD_CARD_ERROR_WRITE); - chipSelectHigh(); - return false; - } - return true; -} -//------------------------------------------------------------------------------ -/** Start a write multiple blocks sequence. - * - * \param[in] blockNumber Address of first block in sequence. - * \param[in] eraseCount The number of blocks to be pre-erased. - * - * \note This function is used with writeData() and writeStop() - * for optimized multiple block writes. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { -#if SD_PROTECT_BLOCK_ZERO - // don't allow write to first block - if (blockNumber == 0) { - error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); - goto fail; - } -#endif // SD_PROTECT_BLOCK_ZERO - // send pre-erase count - if (cardAcmd(ACMD23, eraseCount)) { - error(SD_CARD_ERROR_ACMD23); - goto fail; - } - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD25, blockNumber)) { - error(SD_CARD_ERROR_CMD25); - goto fail; - } - return true; - - fail: - chipSelectHigh(); - return false; -} -//------------------------------------------------------------------------------ -/** End a write multiple blocks sequence. - * -* \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t Sd2Card::writeStop(void) { - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - spiSend(STOP_TRAN_TOKEN); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_STOP_TRAN); - chipSelectHigh(); - return false; -} diff --git a/libraries/SD/src/utility/Sd2Card.h b/libraries/SD/src/utility/Sd2Card.h deleted file mode 100644 index c30e2646..00000000 --- a/libraries/SD/src/utility/Sd2Card.h +++ /dev/null @@ -1,240 +0,0 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card 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 Sd2Card Library. If not, see - * . - */ -#ifndef Sd2Card_h -#define Sd2Card_h -/** - * \file - * Sd2Card class - */ -#include "Sd2PinMap.h" -#include "SdInfo.h" -/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ -uint8_t const SPI_FULL_SPEED = 0; -/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ -uint8_t const SPI_HALF_SPEED = 1; -/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */ -uint8_t const SPI_QUARTER_SPEED = 2; -/** - * USE_SPI_LIB: if set, use the SPI library bundled with Arduino IDE, otherwise - * run with a standalone driver for AVR. - */ -#define USE_SPI_LIB -/** - * Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos. - * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. - * - * MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used - * on Mega Arduinos. Software SPI works well with GPS Shield V1.1 - * but many SD cards will fail with GPS Shield V1.0. - */ -#define MEGA_SOFT_SPI 0 -//------------------------------------------------------------------------------ -#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) -#define SOFTWARE_SPI -#endif // MEGA_SOFT_SPI -//------------------------------------------------------------------------------ -// SPI pin definitions -// -#ifndef SOFTWARE_SPI -// hardware pin defs -/** - * SD Chip Select pin - * - * Warning if this pin is redefined the hardware SS will 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. - */ -/** The default chip select pin for the SD card is SS. */ -uint8_t const SD_CHIP_SELECT_PIN = SS_PIN; -// The following three pins must not be redefined for hardware SPI. -/** SPI Master Out Slave In pin */ -uint8_t const SPI_MOSI_PIN = MOSI_PIN; -/** SPI Master In Slave Out pin */ -uint8_t const SPI_MISO_PIN = MISO_PIN; -/** SPI Clock pin */ -uint8_t const SPI_SCK_PIN = SCK_PIN; -/** optimize loops for hardware SPI */ -#ifndef USE_SPI_LIB -#define OPTIMIZE_HARDWARE_SPI -#endif - -#else // SOFTWARE_SPI -// define software SPI pins so Mega can use unmodified GPS Shield -/** SPI chip select pin */ -uint8_t const SD_CHIP_SELECT_PIN = 10; -/** SPI Master Out Slave In pin */ -uint8_t const SPI_MOSI_PIN = 11; -/** SPI Master In Slave Out pin */ -uint8_t const SPI_MISO_PIN = 12; -/** SPI Clock pin */ -uint8_t const SPI_SCK_PIN = 13; -#endif // SOFTWARE_SPI -//------------------------------------------------------------------------------ -/** Protect block zero from write if nonzero */ -#define SD_PROTECT_BLOCK_ZERO 1 -/** init timeout ms */ -uint16_t const SD_INIT_TIMEOUT = 2000; -/** erase timeout ms */ -uint16_t const SD_ERASE_TIMEOUT = 10000; -/** read timeout ms */ -uint16_t const SD_READ_TIMEOUT = 300; -/** write time out ms */ -uint16_t const SD_WRITE_TIMEOUT = 600; -//------------------------------------------------------------------------------ -// SD card errors -/** timeout error for command CMD0 */ -uint8_t const SD_CARD_ERROR_CMD0 = 0X1; -/** CMD8 was not accepted - not a valid SD card*/ -uint8_t const SD_CARD_ERROR_CMD8 = 0X2; -/** card returned an error response for CMD17 (read block) */ -uint8_t const SD_CARD_ERROR_CMD17 = 0X3; -/** card returned an error response for CMD24 (write block) */ -uint8_t const SD_CARD_ERROR_CMD24 = 0X4; -/** WRITE_MULTIPLE_BLOCKS command failed */ -uint8_t const SD_CARD_ERROR_CMD25 = 0X05; -/** card returned an error response for CMD58 (read OCR) */ -uint8_t const SD_CARD_ERROR_CMD58 = 0X06; -/** SET_WR_BLK_ERASE_COUNT failed */ -uint8_t const SD_CARD_ERROR_ACMD23 = 0X07; -/** card's ACMD41 initialization process timeout */ -uint8_t const SD_CARD_ERROR_ACMD41 = 0X08; -/** card returned a bad CSR version field */ -uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09; -/** erase block group command failed */ -uint8_t const SD_CARD_ERROR_ERASE = 0X0A; -/** card not capable of single block erase */ -uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B; -/** Erase sequence timed out */ -uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C; -/** card returned an error token instead of read data */ -uint8_t const SD_CARD_ERROR_READ = 0X0D; -/** read CID or CSD failed */ -uint8_t const SD_CARD_ERROR_READ_REG = 0X0E; -/** timeout while waiting for start of read data */ -uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F; -/** card did not accept STOP_TRAN_TOKEN */ -uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10; -/** card returned an error token as a response to a write operation */ -uint8_t const SD_CARD_ERROR_WRITE = 0X11; -/** attempt to write protected block zero */ -uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12; -/** card did not go ready for a multiple block write */ -uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13; -/** card returned an error to a CMD13 status check after a write */ -uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14; -/** timeout occurred during write programming */ -uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15; -/** incorrect rate selected */ -uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16; -//------------------------------------------------------------------------------ -// card types -/** Standard capacity V1 SD card */ -uint8_t const SD_CARD_TYPE_SD1 = 1; -/** Standard capacity V2 SD card */ -uint8_t const SD_CARD_TYPE_SD2 = 2; -/** High Capacity SD card */ -uint8_t const SD_CARD_TYPE_SDHC = 3; -//------------------------------------------------------------------------------ -/** - * \class Sd2Card - * \brief Raw access to SD and SDHC flash memory cards. - */ -class Sd2Card { - public: - /** Construct an instance of Sd2Card. */ - Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {} - uint32_t cardSize(void); - uint8_t erase(uint32_t firstBlock, uint32_t lastBlock); - uint8_t eraseSingleBlockEnable(void); - /** - * \return error code for last error. See Sd2Card.h for a list of error codes. - */ - uint8_t errorCode(void) const {return errorCode_;} - /** \return error data for last error. */ - uint8_t errorData(void) const {return status_;} - /** - * Initialize an SD flash memory card with default clock rate and chip - * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). - */ - uint8_t init(void) { - return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN); - } - /** - * Initialize an SD flash memory card with the selected SPI clock rate - * and the default SD chip select pin. - * See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). - */ - uint8_t init(uint8_t sckRateID) { - return init(sckRateID, SD_CHIP_SELECT_PIN); - } - uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin); - void partialBlockRead(uint8_t value); - /** Returns the current value, true or false, for partial block read. */ - uint8_t partialBlockRead(void) const {return partialBlockRead_;} - uint8_t readBlock(uint32_t block, uint8_t* dst); - uint8_t readData(uint32_t block, - uint16_t offset, uint16_t count, uint8_t* dst); - /** - * Read a cards CID register. The CID contains card identification - * information such as Manufacturer ID, Product name, Product serial - * number and Manufacturing date. */ - uint8_t readCID(cid_t* cid) { - return readRegister(CMD10, cid); - } - /** - * Read a cards CSD register. The CSD contains Card-Specific Data that - * provides information regarding access to the card's contents. */ - uint8_t readCSD(csd_t* csd) { - return readRegister(CMD9, csd); - } - void readEnd(void); - uint8_t setSckRate(uint8_t sckRateID); - /** Return the card type: SD V1, SD V2 or SDHC */ - uint8_t type(void) const {return type_;} - uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src); - uint8_t writeData(const uint8_t* src); - uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount); - uint8_t writeStop(void); - private: - uint32_t block_; - uint8_t chipSelectPin_; - uint8_t errorCode_; - uint8_t inBlock_; - uint16_t offset_; - uint8_t partialBlockRead_; - uint8_t status_; - uint8_t type_; - // private functions - uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { - cardCommand(CMD55, 0); - return cardCommand(cmd, arg); - } - uint8_t cardCommand(uint8_t cmd, uint32_t arg); - void error(uint8_t code) {errorCode_ = code;} - uint8_t readRegister(uint8_t cmd, void* buf); - uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); - void chipSelectHigh(void); - void chipSelectLow(void); - void type(uint8_t value) {type_ = value;} - uint8_t waitNotBusy(uint16_t timeoutMillis); - uint8_t writeData(uint8_t token, const uint8_t* src); - uint8_t waitStartBlock(void); -}; -#endif // Sd2Card_h diff --git a/libraries/SD/src/utility/Sd2PinMap.h b/libraries/SD/src/utility/Sd2PinMap.h deleted file mode 100644 index a1042f65..00000000 --- a/libraries/SD/src/utility/Sd2PinMap.h +++ /dev/null @@ -1,387 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2010 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#if defined(__arm__) // Arduino Due Board follows - -#ifndef Sd2PinMap_h -#define Sd2PinMap_h - -#include - -uint8_t const SS_PIN = SS; -uint8_t const MOSI_PIN = MOSI; -uint8_t const MISO_PIN = MISO; -uint8_t const SCK_PIN = SCK; - -#endif // Sd2PinMap_h - -#elif defined(__AVR__) // Other AVR based Boards follows - -// Warning this file was generated by a program. -#ifndef Sd2PinMap_h -#define Sd2PinMap_h -#include - -//------------------------------------------------------------------------------ -/** struct for mapping digital pins */ -struct pin_map_t { - volatile uint8_t* ddr; - volatile uint8_t* pin; - volatile uint8_t* port; - uint8_t bit; -}; -//------------------------------------------------------------------------------ -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -// Mega - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 20; -uint8_t const SCL_PIN = 21; - -// SPI port -uint8_t const SS_PIN = 53; -uint8_t const MOSI_PIN = 51; -uint8_t const MISO_PIN = 50; -uint8_t const SCK_PIN = 52; - -static const pin_map_t digitalPinMap[] = { - {&DDRE, &PINE, &PORTE, 0}, // E0 0 - {&DDRE, &PINE, &PORTE, 1}, // E1 1 - {&DDRE, &PINE, &PORTE, 4}, // E4 2 - {&DDRE, &PINE, &PORTE, 5}, // E5 3 - {&DDRG, &PING, &PORTG, 5}, // G5 4 - {&DDRE, &PINE, &PORTE, 3}, // E3 5 - {&DDRH, &PINH, &PORTH, 3}, // H3 6 - {&DDRH, &PINH, &PORTH, 4}, // H4 7 - {&DDRH, &PINH, &PORTH, 5}, // H5 8 - {&DDRH, &PINH, &PORTH, 6}, // H6 9 - {&DDRB, &PINB, &PORTB, 4}, // B4 10 - {&DDRB, &PINB, &PORTB, 5}, // B5 11 - {&DDRB, &PINB, &PORTB, 6}, // B6 12 - {&DDRB, &PINB, &PORTB, 7}, // B7 13 - {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 - {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 - {&DDRH, &PINH, &PORTH, 1}, // H1 16 - {&DDRH, &PINH, &PORTH, 0}, // H0 17 - {&DDRD, &PIND, &PORTD, 3}, // D3 18 - {&DDRD, &PIND, &PORTD, 2}, // D2 19 - {&DDRD, &PIND, &PORTD, 1}, // D1 20 - {&DDRD, &PIND, &PORTD, 0}, // D0 21 - {&DDRA, &PINA, &PORTA, 0}, // A0 22 - {&DDRA, &PINA, &PORTA, 1}, // A1 23 - {&DDRA, &PINA, &PORTA, 2}, // A2 24 - {&DDRA, &PINA, &PORTA, 3}, // A3 25 - {&DDRA, &PINA, &PORTA, 4}, // A4 26 - {&DDRA, &PINA, &PORTA, 5}, // A5 27 - {&DDRA, &PINA, &PORTA, 6}, // A6 28 - {&DDRA, &PINA, &PORTA, 7}, // A7 29 - {&DDRC, &PINC, &PORTC, 7}, // C7 30 - {&DDRC, &PINC, &PORTC, 6}, // C6 31 - {&DDRC, &PINC, &PORTC, 5}, // C5 32 - {&DDRC, &PINC, &PORTC, 4}, // C4 33 - {&DDRC, &PINC, &PORTC, 3}, // C3 34 - {&DDRC, &PINC, &PORTC, 2}, // C2 35 - {&DDRC, &PINC, &PORTC, 1}, // C1 36 - {&DDRC, &PINC, &PORTC, 0}, // C0 37 - {&DDRD, &PIND, &PORTD, 7}, // D7 38 - {&DDRG, &PING, &PORTG, 2}, // G2 39 - {&DDRG, &PING, &PORTG, 1}, // G1 40 - {&DDRG, &PING, &PORTG, 0}, // G0 41 - {&DDRL, &PINL, &PORTL, 7}, // L7 42 - {&DDRL, &PINL, &PORTL, 6}, // L6 43 - {&DDRL, &PINL, &PORTL, 5}, // L5 44 - {&DDRL, &PINL, &PORTL, 4}, // L4 45 - {&DDRL, &PINL, &PORTL, 3}, // L3 46 - {&DDRL, &PINL, &PORTL, 2}, // L2 47 - {&DDRL, &PINL, &PORTL, 1}, // L1 48 - {&DDRL, &PINL, &PORTL, 0}, // L0 49 - {&DDRB, &PINB, &PORTB, 3}, // B3 50 - {&DDRB, &PINB, &PORTB, 2}, // B2 51 - {&DDRB, &PINB, &PORTB, 1}, // B1 52 - {&DDRB, &PINB, &PORTB, 0}, // B0 53 - {&DDRF, &PINF, &PORTF, 0}, // F0 54 - {&DDRF, &PINF, &PORTF, 1}, // F1 55 - {&DDRF, &PINF, &PORTF, 2}, // F2 56 - {&DDRF, &PINF, &PORTF, 3}, // F3 57 - {&DDRF, &PINF, &PORTF, 4}, // F4 58 - {&DDRF, &PINF, &PORTF, 5}, // F5 59 - {&DDRF, &PINF, &PORTF, 6}, // F6 60 - {&DDRF, &PINF, &PORTF, 7}, // F7 61 - {&DDRK, &PINK, &PORTK, 0}, // K0 62 - {&DDRK, &PINK, &PORTK, 1}, // K1 63 - {&DDRK, &PINK, &PORTK, 2}, // K2 64 - {&DDRK, &PINK, &PORTK, 3}, // K3 65 - {&DDRK, &PINK, &PORTK, 4}, // K4 66 - {&DDRK, &PINK, &PORTK, 5}, // K5 67 - {&DDRK, &PINK, &PORTK, 6}, // K6 68 - {&DDRK, &PINK, &PORTK, 7} // K7 69 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) -// Sanguino - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 17; -uint8_t const SCL_PIN = 18; - -// SPI port -uint8_t const SS_PIN = 4; -uint8_t const MOSI_PIN = 5; -uint8_t const MISO_PIN = 6; -uint8_t const SCK_PIN = 7; - -static const pin_map_t digitalPinMap[] = { - {&DDRB, &PINB, &PORTB, 0}, // B0 0 - {&DDRB, &PINB, &PORTB, 1}, // B1 1 - {&DDRB, &PINB, &PORTB, 2}, // B2 2 - {&DDRB, &PINB, &PORTB, 3}, // B3 3 - {&DDRB, &PINB, &PORTB, 4}, // B4 4 - {&DDRB, &PINB, &PORTB, 5}, // B5 5 - {&DDRB, &PINB, &PORTB, 6}, // B6 6 - {&DDRB, &PINB, &PORTB, 7}, // B7 7 - {&DDRD, &PIND, &PORTD, 0}, // D0 8 - {&DDRD, &PIND, &PORTD, 1}, // D1 9 - {&DDRD, &PIND, &PORTD, 2}, // D2 10 - {&DDRD, &PIND, &PORTD, 3}, // D3 11 - {&DDRD, &PIND, &PORTD, 4}, // D4 12 - {&DDRD, &PIND, &PORTD, 5}, // D5 13 - {&DDRD, &PIND, &PORTD, 6}, // D6 14 - {&DDRD, &PIND, &PORTD, 7}, // D7 15 - {&DDRC, &PINC, &PORTC, 0}, // C0 16 - {&DDRC, &PINC, &PORTC, 1}, // C1 17 - {&DDRC, &PINC, &PORTC, 2}, // C2 18 - {&DDRC, &PINC, &PORTC, 3}, // C3 19 - {&DDRC, &PINC, &PORTC, 4}, // C4 20 - {&DDRC, &PINC, &PORTC, 5}, // C5 21 - {&DDRC, &PINC, &PORTC, 6}, // C6 22 - {&DDRC, &PINC, &PORTC, 7}, // C7 23 - {&DDRA, &PINA, &PORTA, 7}, // A7 24 - {&DDRA, &PINA, &PORTA, 6}, // A6 25 - {&DDRA, &PINA, &PORTA, 5}, // A5 26 - {&DDRA, &PINA, &PORTA, 4}, // A4 27 - {&DDRA, &PINA, &PORTA, 3}, // A3 28 - {&DDRA, &PINA, &PORTA, 2}, // A2 29 - {&DDRA, &PINA, &PORTA, 1}, // A1 30 - {&DDRA, &PINA, &PORTA, 0} // A0 31 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_ATmega32U4__) -// Leonardo - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 2; -uint8_t const SCL_PIN = 3; - -// SPI port -uint8_t const SS_PIN = 17; -uint8_t const MOSI_PIN = 16; -uint8_t const MISO_PIN = 14; -uint8_t const SCK_PIN = 15; - -static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 2}, // D2 0 - {&DDRD, &PIND, &PORTD, 3}, // D3 1 - {&DDRD, &PIND, &PORTD, 1}, // D1 2 - {&DDRD, &PIND, &PORTD, 0}, // D0 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRC, &PINC, &PORTC, 6}, // C6 5 - {&DDRD, &PIND, &PORTD, 7}, // D7 6 - {&DDRE, &PINE, &PORTE, 6}, // E6 7 - {&DDRB, &PINB, &PORTB, 4}, // B4 8 - {&DDRB, &PINB, &PORTB, 5}, // B5 9 - {&DDRB, &PINB, &PORTB, 6}, // B6 10 - {&DDRB, &PINB, &PORTB, 7}, // B7 11 - {&DDRD, &PIND, &PORTD, 6}, // D6 12 - {&DDRC, &PINC, &PORTC, 7}, // C7 13 - {&DDRB, &PINB, &PORTB, 3}, // B3 14 - {&DDRB, &PINB, &PORTB, 1}, // B1 15 - {&DDRB, &PINB, &PORTB, 2}, // B2 16 - {&DDRB, &PINB, &PORTB, 0}, // B0 17 - {&DDRF, &PINF, &PORTF, 7}, // F7 18 - {&DDRF, &PINF, &PORTF, 6}, // F6 19 - {&DDRF, &PINF, &PORTF, 5}, // F5 20 - {&DDRF, &PINF, &PORTF, 4}, // F4 21 - {&DDRF, &PINF, &PORTF, 1}, // F1 22 - {&DDRF, &PINF, &PORTF, 0}, // F0 23 -}; -//------------------------------------------------------------------------------ -#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) -// Teensy++ 1.0 & 2.0 - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 1; -uint8_t const SCL_PIN = 0; - -// SPI port -uint8_t const SS_PIN = 20; -uint8_t const MOSI_PIN = 22; -uint8_t const MISO_PIN = 23; -uint8_t const SCK_PIN = 21; - -static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 0}, // D0 0 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRE, &PINE, &PORTE, 0}, // E0 8 - {&DDRE, &PINE, &PORTE, 1}, // E1 9 - {&DDRC, &PINC, &PORTC, 0}, // C0 10 - {&DDRC, &PINC, &PORTC, 1}, // C1 11 - {&DDRC, &PINC, &PORTC, 2}, // C2 12 - {&DDRC, &PINC, &PORTC, 3}, // C3 13 - {&DDRC, &PINC, &PORTC, 4}, // C4 14 - {&DDRC, &PINC, &PORTC, 5}, // C5 15 - {&DDRC, &PINC, &PORTC, 6}, // C6 16 - {&DDRC, &PINC, &PORTC, 7}, // C7 17 - {&DDRE, &PINE, &PORTE, 6}, // E6 18 - {&DDRE, &PINE, &PORTE, 7}, // E7 19 - {&DDRB, &PINB, &PORTB, 0}, // B0 20 - {&DDRB, &PINB, &PORTB, 1}, // B1 21 - {&DDRB, &PINB, &PORTB, 2}, // B2 22 - {&DDRB, &PINB, &PORTB, 3}, // B3 23 - {&DDRB, &PINB, &PORTB, 4}, // B4 24 - {&DDRB, &PINB, &PORTB, 5}, // B5 25 - {&DDRB, &PINB, &PORTB, 6}, // B6 26 - {&DDRB, &PINB, &PORTB, 7}, // B7 27 - {&DDRA, &PINA, &PORTA, 0}, // A0 28 - {&DDRA, &PINA, &PORTA, 1}, // A1 29 - {&DDRA, &PINA, &PORTA, 2}, // A2 30 - {&DDRA, &PINA, &PORTA, 3}, // A3 31 - {&DDRA, &PINA, &PORTA, 4}, // A4 32 - {&DDRA, &PINA, &PORTA, 5}, // A5 33 - {&DDRA, &PINA, &PORTA, 6}, // A6 34 - {&DDRA, &PINA, &PORTA, 7}, // A7 35 - {&DDRE, &PINE, &PORTE, 4}, // E4 36 - {&DDRE, &PINE, &PORTE, 5}, // E5 37 - {&DDRF, &PINF, &PORTF, 0}, // F0 38 - {&DDRF, &PINF, &PORTF, 1}, // F1 39 - {&DDRF, &PINF, &PORTF, 2}, // F2 40 - {&DDRF, &PINF, &PORTF, 3}, // F3 41 - {&DDRF, &PINF, &PORTF, 4}, // F4 42 - {&DDRF, &PINF, &PORTF, 5}, // F5 43 - {&DDRF, &PINF, &PORTF, 6}, // F6 44 - {&DDRF, &PINF, &PORTF, 7} // F7 45 -}; -//------------------------------------------------------------------------------ -#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -// 168 and 328 Arduinos - -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 18; -uint8_t const SCL_PIN = 19; - -// SPI port -uint8_t const SS_PIN = 10; -uint8_t const MOSI_PIN = 11; -uint8_t const MISO_PIN = 12; -uint8_t const SCK_PIN = 13; - -static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 0}, // D0 0 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRB, &PINB, &PORTB, 0}, // B0 8 - {&DDRB, &PINB, &PORTB, 1}, // B1 9 - {&DDRB, &PINB, &PORTB, 2}, // B2 10 - {&DDRB, &PINB, &PORTB, 3}, // B3 11 - {&DDRB, &PINB, &PORTB, 4}, // B4 12 - {&DDRB, &PINB, &PORTB, 5}, // B5 13 - {&DDRC, &PINC, &PORTC, 0}, // C0 14 - {&DDRC, &PINC, &PORTC, 1}, // C1 15 - {&DDRC, &PINC, &PORTC, 2}, // C2 16 - {&DDRC, &PINC, &PORTC, 3}, // C3 17 - {&DDRC, &PINC, &PORTC, 4}, // C4 18 - {&DDRC, &PINC, &PORTC, 5} // C5 19 -}; -#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -//------------------------------------------------------------------------------ -static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); - -uint8_t badPinNumber(void) - __attribute__((error("Pin number is too large or not a constant"))); - -static inline __attribute__((always_inline)) - uint8_t getPinMode(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } -} -static inline __attribute__((always_inline)) - void setPinMode(uint8_t pin, uint8_t mode) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (mode) { - *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; - } else { - *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); - } - } else { - badPinNumber(); - } -} -static inline __attribute__((always_inline)) - uint8_t fastDigitalRead(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } -} -static inline __attribute__((always_inline)) - void fastDigitalWrite(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (value) { - *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; - } else { - *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); - } - } else { - badPinNumber(); - } -} -#endif // Sd2PinMap_h - -#elif defined (__CPU_ARC__) - -#if defined (__ARDUINO_ARC__) -// Two Wire (aka I2C) ports -uint8_t const SDA_PIN = 18; -uint8_t const SCL_PIN = 19; - -// SPI port -uint8_t const SS_PIN = 10; -uint8_t const MOSI_PIN = 11; -uint8_t const MISO_PIN = 12; -uint8_t const SCK_PIN = 13; - -#endif // Arduino ARC - -#else -#error Architecture or board not supported. -#endif diff --git a/libraries/SD/src/utility/SdFat.h b/libraries/SD/src/utility/SdFat.h deleted file mode 100644 index cdf22251..00000000 --- a/libraries/SD/src/utility/SdFat.h +++ /dev/null @@ -1,551 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#ifndef SdFat_h -#define SdFat_h -/** - * \file - * SdFile and SdVolume classes - */ -#if defined (__AVR__) || defined (__CPU_ARC__) -#include -#endif -#include "Sd2Card.h" -#include "FatStructs.h" -#include "Print.h" -//------------------------------------------------------------------------------ -/** - * Allow use of deprecated functions if non-zero - */ -#define ALLOW_DEPRECATED_FUNCTIONS 1 -//------------------------------------------------------------------------------ -// forward declaration since SdVolume is used in SdFile -class SdVolume; -//============================================================================== -// SdFile class - -// flags for ls() -/** ls() flag to print modify date */ -uint8_t const LS_DATE = 1; -/** ls() flag to print file size */ -uint8_t const LS_SIZE = 2; -/** ls() flag for recursive list of subdirectories */ -uint8_t const LS_R = 4; - -// use the gnu style oflag in open() -/** open() oflag for reading */ -uint8_t const O_READ = 0X01; -/** open() oflag - same as O_READ */ -uint8_t const O_RDONLY = O_READ; -/** open() oflag for write */ -uint8_t const O_WRITE = 0X02; -/** open() oflag - same as O_WRITE */ -uint8_t const O_WRONLY = O_WRITE; -/** open() oflag for reading and writing */ -uint8_t const O_RDWR = (O_READ | O_WRITE); -/** open() oflag mask for access modes */ -uint8_t const O_ACCMODE = (O_READ | O_WRITE); -/** The file offset shall be set to the end of the file prior to each write. */ -uint8_t const O_APPEND = 0X04; -/** synchronous writes - call sync() after each write */ -uint8_t const O_SYNC = 0X08; -/** create the file if nonexistent */ -uint8_t const O_CREAT = 0X10; -/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ -uint8_t const O_EXCL = 0X20; -/** truncate the file to zero length */ -uint8_t const O_TRUNC = 0X40; - -// flags for timestamp -/** set the file's last access date */ -uint8_t const T_ACCESS = 1; -/** set the file's creation date and time */ -uint8_t const T_CREATE = 2; -/** Set the file's write date and time */ -uint8_t const T_WRITE = 4; -// values for type_ -/** This SdFile has not been opened. */ -uint8_t const FAT_FILE_TYPE_CLOSED = 0; -/** SdFile for a file */ -uint8_t const FAT_FILE_TYPE_NORMAL = 1; -/** SdFile for a FAT16 root directory */ -uint8_t const FAT_FILE_TYPE_ROOT16 = 2; -/** SdFile for a FAT32 root directory */ -uint8_t const FAT_FILE_TYPE_ROOT32 = 3; -/** SdFile for a subdirectory */ -uint8_t const FAT_FILE_TYPE_SUBDIR = 4; -/** Test value for directory type */ -uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16; - -/** date field for FAT directory entry */ -static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { - return (year - 1980) << 9 | month << 5 | day; -} -/** year part of FAT directory date field */ -static inline uint16_t FAT_YEAR(uint16_t fatDate) { - return 1980 + (fatDate >> 9); -} -/** month part of FAT directory date field */ -static inline uint8_t FAT_MONTH(uint16_t fatDate) { - return (fatDate >> 5) & 0XF; -} -/** day part of FAT directory date field */ -static inline uint8_t FAT_DAY(uint16_t fatDate) { - return fatDate & 0X1F; -} -/** time field for FAT directory entry */ -static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { - return hour << 11 | minute << 5 | second >> 1; -} -/** hour part of FAT directory time field */ -static inline uint8_t FAT_HOUR(uint16_t fatTime) { - return fatTime >> 11; -} -/** minute part of FAT directory time field */ -static inline uint8_t FAT_MINUTE(uint16_t fatTime) { - return(fatTime >> 5) & 0X3F; -} -/** second part of FAT directory time field */ -static inline uint8_t FAT_SECOND(uint16_t fatTime) { - return 2*(fatTime & 0X1F); -} -/** Default date for file timestamps is 1 Jan 2000 */ -uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; -/** Default time for file timestamp is 1 am */ -uint16_t const FAT_DEFAULT_TIME = (1 << 11); -//------------------------------------------------------------------------------ -/** - * \class SdFile - * \brief Access FAT16 and FAT32 files on SD and SDHC cards. - */ -class SdFile : public Print { - public: - /** Create an instance of SdFile. */ - SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {} - /** - * writeError is set to true if an error occurs during a write(). - * Set writeError to false before calling print() and/or write() and check - * for true after calls to print() and/or write(). - */ - //bool writeError; - /** - * Cancel unbuffered reads for this file. - * See setUnbufferedRead() - */ - void clearUnbufferedRead(void) { - flags_ &= ~F_FILE_UNBUFFERED_READ; - } - uint8_t close(void); - uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); - uint8_t createContiguous(SdFile* dirFile, - const char* fileName, uint32_t size); - /** \return The current cluster number for a file or directory. */ - uint32_t curCluster(void) const {return curCluster_;} - /** \return The current position for a file or directory. */ - uint32_t curPosition(void) const {return curPosition_;} - /** - * Set the date/time callback function - * - * \param[in] dateTime The user's call back function. The callback - * function is of the form: - * - * \code - * void dateTime(uint16_t* date, uint16_t* time) { - * uint16_t year; - * uint8_t month, day, hour, minute, second; - * - * // User gets date and time from GPS or real-time clock here - * - * // return date using FAT_DATE macro to format fields - * *date = FAT_DATE(year, month, day); - * - * // return time using FAT_TIME macro to format fields - * *time = FAT_TIME(hour, minute, second); - * } - * \endcode - * - * Sets the function that is called when a file is created or when - * a file's directory entry is modified by sync(). All timestamps, - * access, creation, and modify, are set when a file is created. - * sync() maintains the last access date and last modify date/time. - * - * See the timestamp() function. - */ - static void dateTimeCallback( - void (*dateTime)(uint16_t* date, uint16_t* time)) { - dateTime_ = dateTime; - } - /** - * Cancel the date/time callback function. - */ - static void dateTimeCallbackCancel(void) { - // use explicit zero since NULL is not defined for Sanguino - dateTime_ = 0; - } - /** \return Address of the block that contains this file's directory. */ - uint32_t dirBlock(void) const {return dirBlock_;} - uint8_t dirEntry(dir_t* dir); - /** \return Index of this file's directory in the block dirBlock. */ - uint8_t dirIndex(void) const {return dirIndex_;} - static void dirName(const dir_t& dir, char* name); - /** \return The total number of bytes in a file or directory. */ - uint32_t fileSize(void) const {return fileSize_;} - /** \return The first cluster number for a file or directory. */ - uint32_t firstCluster(void) const {return firstCluster_;} - /** \return True if this is a SdFile for a directory else false. */ - uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} - /** \return True if this is a SdFile for a file else false. */ - uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;} - /** \return True if this is a SdFile for an open file/directory else false. */ - uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;} - /** \return True if this is a SdFile for a subdirectory else false. */ - uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;} - /** \return True if this is a SdFile for the root directory. */ - uint8_t isRoot(void) const { - return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32; - } - void ls(uint8_t flags = 0, uint8_t indent = 0); - uint8_t makeDir(SdFile* dir, const char* dirName); - uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag); - uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag); - - uint8_t openRoot(SdVolume* vol); - static void printDirName(const dir_t& dir, uint8_t width); - static void printFatDate(uint16_t fatDate); - static void printFatTime(uint16_t fatTime); - static void printTwoDigits(uint8_t v); - /** - * Read the next byte from a file. - * - * \return For success read returns the next byte in the file as an int. - * If an error occurs or end of file is reached -1 is returned. - */ - int16_t read(void) { - uint8_t b; - return read(&b, 1) == 1 ? b : -1; - } - int16_t read(void* buf, uint16_t nbyte); - int8_t readDir(dir_t* dir); - static uint8_t remove(SdFile* dirFile, const char* fileName); - uint8_t remove(void); - /** Set the file's current position to zero. */ - void rewind(void) { - curPosition_ = curCluster_ = 0; - } - uint8_t rmDir(void); - uint8_t rmRfStar(void); - /** Set the files position to current position + \a pos. See seekSet(). */ - uint8_t seekCur(uint32_t pos) { - return seekSet(curPosition_ + pos); - } - /** - * Set the files current position to end of file. Useful to position - * a file for append. See seekSet(). - */ - uint8_t seekEnd(void) {return seekSet(fileSize_);} - uint8_t seekSet(uint32_t pos); - /** - * Use unbuffered reads to access this file. Used with Wave - * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP. - * - * Not recommended for normal applications. - */ - void setUnbufferedRead(void) { - if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ; - } - uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, - uint8_t hour, uint8_t minute, uint8_t second); - uint8_t sync(void); - /** Type of this SdFile. You should use isFile() or isDir() instead of type() - * if possible. - * - * \return The file or directory type. - */ - uint8_t type(void) const {return type_;} - uint8_t truncate(uint32_t size); - /** \return Unbuffered read flag. */ - uint8_t unbufferedRead(void) const { - return flags_ & F_FILE_UNBUFFERED_READ; - } - /** \return SdVolume that contains this file. */ - SdVolume* volume(void) const {return vol_;} - size_t write(uint8_t b); - size_t write(const void* buf, uint16_t nbyte); - size_t write(const char* str); -#ifdef __AVR__ - void write_P(PGM_P str); - void writeln_P(PGM_P str); -#endif -//------------------------------------------------------------------------------ -#if ALLOW_DEPRECATED_FUNCTIONS -// Deprecated functions - suppress cpplint warnings with NOLINT comment - /** \deprecated Use: - * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); - */ - uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT - return contiguousRange(&bgnBlock, &endBlock); - } - /** \deprecated Use: - * uint8_t SdFile::createContiguous(SdFile* dirFile, - * const char* fileName, uint32_t size) - */ - uint8_t createContiguous(SdFile& dirFile, // NOLINT - const char* fileName, uint32_t size) { - return createContiguous(&dirFile, fileName, size); - } - - /** - * \deprecated Use: - * static void SdFile::dateTimeCallback( - * void (*dateTime)(uint16_t* date, uint16_t* time)); - */ - static void dateTimeCallback( - void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT - oldDateTime_ = dateTime; - dateTime_ = dateTime ? oldToNew : 0; - } - /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */ - uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT - /** \deprecated Use: - * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName); - */ - uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT - return makeDir(&dir, dirName); - } - /** \deprecated Use: - * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag); - */ - uint8_t open(SdFile& dirFile, // NOLINT - const char* fileName, uint8_t oflag) { - return open(&dirFile, fileName, oflag); - } - /** \deprecated Do not use in new apps */ - uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT - return open(dirFile, fileName, O_RDWR); - } - /** \deprecated Use: - * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag); - */ - uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT - return open(&dirFile, index, oflag); - } - /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */ - uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT - - /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */ - int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT - /** \deprecated Use: - * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName); - */ - static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT - return remove(&dirFile, fileName); - } -//------------------------------------------------------------------------------ -// rest are private - private: - static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT - static void oldToNew(uint16_t* date, uint16_t* time) { - uint16_t d; - uint16_t t; - oldDateTime_(d, t); - *date = d; - *time = t; - } -#endif // ALLOW_DEPRECATED_FUNCTIONS - private: - // bits defined in flags_ - // should be 0XF - static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); - // available bits - static uint8_t const F_UNUSED = 0X30; - // use unbuffered SD read - static uint8_t const F_FILE_UNBUFFERED_READ = 0X40; - // sync of directory entry required - static uint8_t const F_FILE_DIR_DIRTY = 0X80; - -// make sure F_OFLAG is ok -#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG) -#error flags_ bits conflict -#endif // flags_ bits - - // private data - uint8_t flags_; // See above for definition of flags_ bits - uint8_t type_; // type of file see above for values - uint32_t curCluster_; // cluster for current file position - uint32_t curPosition_; // current file position in bytes from beginning - uint32_t dirBlock_; // SD block that contains directory entry for file - uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF - uint32_t fileSize_; // file size in bytes - uint32_t firstCluster_; // first cluster of file - SdVolume* vol_; // volume where file is located - - // private functions - uint8_t addCluster(void); - uint8_t addDirCluster(void); - dir_t* cacheDirEntry(uint8_t action); - static void (*dateTime_)(uint16_t* date, uint16_t* time); - static uint8_t make83Name(const char* str, uint8_t* name); - uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags); - dir_t* readDirCache(void); -}; -//============================================================================== -// SdVolume class -/** - * \brief Cache for an SD data block - */ -union cache_t { - /** Used to access cached file data blocks. */ - uint8_t data[512]; - /** Used to access cached FAT16 entries. */ - uint16_t fat16[256]; - /** Used to access cached FAT32 entries. */ - uint32_t fat32[128]; - /** Used to access cached directory entries. */ - dir_t dir[16]; - /** Used to access a cached MasterBoot Record. */ - mbr_t mbr; - /** Used to access to a cached FAT boot sector. */ - fbs_t fbs; -}; -//------------------------------------------------------------------------------ -/** - * \class SdVolume - * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. - */ -class SdVolume { - public: - /** Create an instance of SdVolume */ - SdVolume(void) :allocSearchStart_(2), fatType_(0) {} - /** Clear the cache and returns a pointer to the cache. Used by the WaveRP - * recorder to do raw write to the SD card. Not for normal apps. - */ - static uint8_t* cacheClear(void) { - cacheFlush(); - cacheBlockNumber_ = 0XFFFFFFFF; - return cacheBuffer_.data; - } - /** - * Initialize a FAT volume. Try partition one first then try super - * floppy format. - * - * \param[in] dev The Sd2Card where the volume is located. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. Reasons for - * failure include not finding a valid partition, not finding a valid - * FAT file system or an I/O error. - */ - uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);} - uint8_t init(Sd2Card* dev, uint8_t part); - - // inline functions that return volume info - /** \return The volume's cluster size in blocks. */ - uint8_t blocksPerCluster(void) const {return blocksPerCluster_;} - /** \return The number of blocks in one FAT. */ - uint32_t blocksPerFat(void) const {return blocksPerFat_;} - /** \return The total number of clusters in the volume. */ - uint32_t clusterCount(void) const {return clusterCount_;} - /** \return The shift count required to multiply by blocksPerCluster. */ - uint8_t clusterSizeShift(void) const {return clusterSizeShift_;} - /** \return The logical block number for the start of file data. */ - uint32_t dataStartBlock(void) const {return dataStartBlock_;} - /** \return The number of FAT structures on the volume. */ - uint8_t fatCount(void) const {return fatCount_;} - /** \return The logical block number for the start of the first FAT. */ - uint32_t fatStartBlock(void) const {return fatStartBlock_;} - /** \return The FAT type of the volume. Values are 12, 16 or 32. */ - uint8_t fatType(void) const {return fatType_;} - /** \return The number of entries in the root directory for FAT16 volumes. */ - uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;} - /** \return The logical block number for the start of the root directory - on FAT16 volumes or the first cluster number on FAT32 volumes. */ - uint32_t rootDirStart(void) const {return rootDirStart_;} - /** return a pointer to the Sd2Card object for this volume */ - static Sd2Card* sdCard(void) {return sdCard_;} -//------------------------------------------------------------------------------ -#if ALLOW_DEPRECATED_FUNCTIONS - // Deprecated functions - suppress cpplint warnings with NOLINT comment - /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */ - uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT - - /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */ - uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT - return init(&dev, part); - } -#endif // ALLOW_DEPRECATED_FUNCTIONS -//------------------------------------------------------------------------------ - private: - // Allow SdFile access to SdVolume private data. - friend class SdFile; - - // value for action argument in cacheRawBlock to indicate read from cache - static uint8_t const CACHE_FOR_READ = 0; - // value for action argument in cacheRawBlock to indicate cache dirty - static uint8_t const CACHE_FOR_WRITE = 1; - - static cache_t cacheBuffer_; // 512 byte cache for device blocks - static uint32_t cacheBlockNumber_; // Logical number of block in the cache - static Sd2Card* sdCard_; // Sd2Card object for cache - static uint8_t cacheDirty_; // cacheFlush() will write block if true - static uint32_t cacheMirrorBlock_; // block number for mirror FAT -// - uint32_t allocSearchStart_; // start cluster for alloc search - uint8_t blocksPerCluster_; // cluster size in blocks - uint32_t blocksPerFat_; // FAT size in blocks - uint32_t clusterCount_; // clusters in one FAT - uint8_t clusterSizeShift_; // shift to convert cluster count to block count - uint32_t dataStartBlock_; // first data block number - uint8_t fatCount_; // number of FATs on volume - uint32_t fatStartBlock_; // start block for first FAT - uint8_t fatType_; // volume type (12, 16, OR 32) - uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir - uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 - //---------------------------------------------------------------------------- - uint8_t allocContiguous(uint32_t count, uint32_t* curCluster); - uint8_t blockOfCluster(uint32_t position) const { - return (position >> 9) & (blocksPerCluster_ - 1);} - uint32_t clusterStartBlock(uint32_t cluster) const { - return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} - uint32_t blockNumber(uint32_t cluster, uint32_t position) const { - return clusterStartBlock(cluster) + blockOfCluster(position);} - static uint8_t cacheFlush(void); - static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action); - static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;} - static uint8_t cacheZeroBlock(uint32_t blockNumber); - uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const; - uint8_t fatGet(uint32_t cluster, uint32_t* value) const; - uint8_t fatPut(uint32_t cluster, uint32_t value); - uint8_t fatPutEOC(uint32_t cluster) { - return fatPut(cluster, 0x0FFFFFFF); - } - uint8_t freeChain(uint32_t cluster); - uint8_t isEOC(uint32_t cluster) const { - return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN); - } - uint8_t readBlock(uint32_t block, uint8_t* dst) { - return sdCard_->readBlock(block, dst);} - uint8_t readData(uint32_t block, uint16_t offset, - uint16_t count, uint8_t* dst) { - return sdCard_->readData(block, offset, count, dst); - } - uint8_t writeBlock(uint32_t block, const uint8_t* dst) { - return sdCard_->writeBlock(block, dst); - } -}; -#endif // SdFat_h diff --git a/libraries/SD/src/utility/SdFatUtil.h b/libraries/SD/src/utility/SdFatUtil.h deleted file mode 100644 index 0812ca4b..00000000 --- a/libraries/SD/src/utility/SdFatUtil.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2008 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#ifndef SdFatUtil_h -#define SdFatUtil_h -/** - * \file - * Useful utility functions. - */ -#include -#ifdef __AVR__ -#include -/** Store and print a string in flash memory.*/ -#define PgmPrint(x) SerialPrint_P(PSTR(x)) -/** Store and print a string in flash memory followed by a CR/LF.*/ -#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) -/** Defined so doxygen works for function definitions. */ -#endif -#define NOINLINE __attribute__((noinline,unused)) -#define UNUSEDOK __attribute__((unused)) -//------------------------------------------------------------------------------ -/** Return the number of bytes currently free in RAM. */ -static UNUSEDOK int FreeRam(void) { - extern int __bss_end; - extern int* __brkval; - int free_memory; - if (reinterpret_cast(__brkval) == 0) { - // if no heap use from end of bss section - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(&__bss_end); - } else { - // use from top of stack to heap - free_memory = reinterpret_cast(&free_memory) - - reinterpret_cast(__brkval); - } - return free_memory; -} -#ifdef __AVR__ -//------------------------------------------------------------------------------ -/** - * %Print a string in flash memory to the serial port. - * - * \param[in] str Pointer to string stored in flash memory. - */ -static NOINLINE void SerialPrint_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c); -} -//------------------------------------------------------------------------------ -/** - * %Print a string in flash memory followed by a CR/LF. - * - * \param[in] str Pointer to string stored in flash memory. - */ -static NOINLINE void SerialPrintln_P(PGM_P str) { - SerialPrint_P(str); - Serial.println(); -} -#endif // __AVR__ -#endif // #define SdFatUtil_h diff --git a/libraries/SD/src/utility/SdFatmainpage.h b/libraries/SD/src/utility/SdFatmainpage.h deleted file mode 100644 index d26cb854..00000000 --- a/libraries/SD/src/utility/SdFatmainpage.h +++ /dev/null @@ -1,202 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ - -/** -\mainpage Arduino SdFat Library -
Copyright © 2009 by William Greiman -
- -\section Intro Introduction -The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32 -file systems on SD flash memory cards. Standard SD and high capacity -SDHC cards are supported. - -The SdFat only supports short 8.3 names. - -The main classes in SdFat are Sd2Card, SdVolume, and SdFile. - -The Sd2Card class supports access to standard SD cards and SDHC cards. Most -applications will only need to call the Sd2Card::init() member function. - -The SdVolume class supports FAT16 and FAT32 partitions. Most applications -will only need to call the SdVolume::init() member function. - -The SdFile class provides file access functions such as open(), read(), -remove(), write(), close() and sync(). This class supports access to the root -directory and subdirectories. - -A number of example are provided in the SdFat/examples folder. These were -developed to test SdFat and illustrate its use. - -SdFat was developed for high speed data recording. SdFat was used to implement -an audio record/play class, WaveRP, for the Adafruit Wave Shield. This -application uses special Sd2Card calls to write to contiguous files in raw mode. -These functions reduce write latency so that audio can be recorded with the -small amount of RAM in the Arduino. - -\section SDcard SD\SDHC 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. - -\section Hardware Hardware Configuration - -SdFat was developed using an - Adafruit Industries - Wave Shield. - -The hardware interface to the SD card should not use a resistor based level -shifter. SdFat 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(SPI_HALF_SPEED) to initialize the SD card. - -\section comment Bugs and Comments - -If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net. - -\section SdFatClass SdFat Usage - -SdFat 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. - -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. - -\note - The Arduino Print class uses character -at a time writes so it was necessary to use a \link SdFile::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 SdFile::write write() \endlink must call \link SdFile::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 SdFile::close() close() \endlink is called. - -\par -Applications must use care calling \link SdFile::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. - -It is possible to open a file with two or more instances of SdFile. A file may -be corrupted if data is written to the file by more than one instance of SdFile. - -\section HowTo How to format SD Cards as FAT Volumes - -You should use a freshly formatted SD card for best performance. FAT -file systems become slower if many files have been created and deleted. -This is because the directory entry for a deleted file is marked as deleted, -but is not deleted. When a new file is created, these entries must be scanned -before creating the file, a flaw in the FAT design. Also files can become -fragmented which causes reads and writes to be slower. - -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 format is to use SDFormatter -which can be downloaded from: - -http://www.sdcard.org/consumers/formatter/ - -SDFormatter aligns flash erase boundaries with file -system structures which reduces write latency and file system overhead. - -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. - -If you reformat the SD card 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 - -Adafruit Industries: - -http://www.adafruit.com/ - -http://www.ladyada.net/make/waveshield/ - -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 - - - */ diff --git a/libraries/SD/src/utility/SdFile.cpp b/libraries/SD/src/utility/SdFile.cpp deleted file mode 100644 index d7bd792d..00000000 --- a/libraries/SD/src/utility/SdFile.cpp +++ /dev/null @@ -1,1263 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#include "SdFat.h" -#ifdef __AVR__ -#include -#endif -#include -//------------------------------------------------------------------------------ -// callback function for date/time -void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; - -#if ALLOW_DEPRECATED_FUNCTIONS -// suppress cpplint warnings with NOLINT comment -void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT -#endif // ALLOW_DEPRECATED_FUNCTIONS -//------------------------------------------------------------------------------ -// add a cluster to a file -uint8_t SdFile::addCluster() { - if (!vol_->allocContiguous(1, &curCluster_)) return false; - - // if first cluster of file link to directory entry - if (firstCluster_ == 0) { - firstCluster_ = curCluster_; - flags_ |= F_FILE_DIR_DIRTY; - } - return true; -} -//------------------------------------------------------------------------------ -// Add a cluster to a directory file and zero the cluster. -// return with first block of cluster in the cache -uint8_t SdFile::addDirCluster(void) { - if (!addCluster()) return false; - - // zero data in cluster insure first cluster is in cache - uint32_t block = vol_->clusterStartBlock(curCluster_); - for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { - if (!SdVolume::cacheZeroBlock(block + i - 1)) return false; - } - // Increase directory file size by cluster size - fileSize_ += 512UL << vol_->clusterSizeShift_; - return true; -} -//------------------------------------------------------------------------------ -// cache a file's directory entry -// return pointer to cached entry or null for failure -dir_t* SdFile::cacheDirEntry(uint8_t action) { - if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; - return SdVolume::cacheBuffer_.dir + dirIndex_; -} -//------------------------------------------------------------------------------ -/** - * Close a file and force cached data and directory information - * to be written to the storage device. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include no file is open or an I/O error. - */ -uint8_t SdFile::close(void) { - if (!sync())return false; - type_ = FAT_FILE_TYPE_CLOSED; - return true; -} -//------------------------------------------------------------------------------ -/** - * Check for contiguous file and return its raw block range. - * - * \param[out] bgnBlock the first block address for the file. - * \param[out] endBlock the last block address for the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include file is not contiguous, file has zero length - * or an I/O error occurred. - */ -uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { - // error if no blocks - if (firstCluster_ == 0) return false; - - for (uint32_t c = firstCluster_; ; c++) { - uint32_t next; - if (!vol_->fatGet(c, &next)) return false; - - // check for contiguous - if (next != (c + 1)) { - // error if not end of chain - if (!vol_->isEOC(next)) return false; - *bgnBlock = vol_->clusterStartBlock(firstCluster_); - *endBlock = vol_->clusterStartBlock(c) - + vol_->blocksPerCluster_ - 1; - return true; - } - } -} -//------------------------------------------------------------------------------ -/** - * Create and open a new contiguous file of a specified size. - * - * \note This function only supports short DOS 8.3 names. - * See open() for more information. - * - * \param[in] dirFile The directory where the file will be created. - * \param[in] fileName A valid DOS 8.3 file name. - * \param[in] size The desired file size. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include \a fileName contains - * an invalid DOS 8.3 file name, the FAT volume has not been initialized, - * a file is already open, the file already exists, the root - * directory is full or an I/O error. - * - */ -uint8_t SdFile::createContiguous(SdFile* dirFile, - const char* fileName, uint32_t size) { - // don't allow zero length file - if (size == 0) return false; - if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false; - - // calculate number of clusters needed - uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; - - // allocate clusters - if (!vol_->allocContiguous(count, &firstCluster_)) { - remove(); - return false; - } - fileSize_ = size; - - // insure sync() will update dir entry - flags_ |= F_FILE_DIR_DIRTY; - return sync(); -} -//------------------------------------------------------------------------------ -/** - * Return a files directory entry - * - * \param[out] dir Location for return of the files directory entry. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::dirEntry(dir_t* dir) { - // make sure fields on SD are correct - if (!sync()) return false; - - // read entry - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); - if (!p) return false; - - // copy to caller's struct - memcpy(dir, p, sizeof(dir_t)); - return true; -} -//------------------------------------------------------------------------------ -/** - * Format the name field of \a dir into the 13 byte array - * \a name in standard 8.3 short name format. - * - * \param[in] dir The directory structure containing the name. - * \param[out] name A 13 byte char array for the formatted name. - */ -void SdFile::dirName(const dir_t& dir, char* name) { - uint8_t j = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) name[j++] = '.'; - name[j++] = dir.name[i]; - } - name[j] = 0; -} -//------------------------------------------------------------------------------ -/** List directory contents to Serial. - * - * \param[in] flags The inclusive OR of - * - * LS_DATE - %Print file modification date - * - * LS_SIZE - %Print file size. - * - * LS_R - Recursive list of subdirectories. - * - * \param[in] indent Amount of space before file name. Used for recursive - * list to indicate subdirectory level. - */ -void SdFile::ls(uint8_t flags, uint8_t indent) { - dir_t* p; - - rewind(); - while ((p = readDirCache())) { - // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) break; - - // skip deleted entry and entries for . and .. - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - - // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; - - // print any indent spaces - for (int8_t i = 0; i < indent; i++) Serial.print(' '); - - // print file name with possible blank fill - printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); - - // print modify date/time if requested - if (flags & LS_DATE) { - printFatDate(p->lastWriteDate); - Serial.print(' '); - printFatTime(p->lastWriteTime); - } - // print size if requested - if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { - Serial.print(' '); - Serial.print(p->fileSize); - } - Serial.println(); - - // list subdirectory content if requested - if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { - uint16_t index = curPosition()/32 - 1; - SdFile s; - if (s.open(this, index, O_READ)) s.ls(flags, indent + 2); - seekSet(32 * (index + 1)); - } - } -} -//------------------------------------------------------------------------------ -// format directory name field from a 8.3 name string -uint8_t SdFile::make83Name(const char* str, uint8_t* name) { - uint8_t c; - uint8_t n = 7; // max index for part before dot - uint8_t i = 0; - // blank fill name and extension - while (i < 11) name[i++] = ' '; - i = 0; - while ((c = *str++) != '\0') { - if (c == '.') { - if (n == 10) return false; // only one dot allowed - n = 10; // max index for full 8.3 name - i = 8; // place for extension - } else { - // illegal FAT characters - uint8_t b; -#if defined(__AVR__) - PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); - while ((b = pgm_read_byte(p++))) if (b == c) return false; -#elif defined(__arm__) - const uint8_t valid[] = "|<>^+=?/[];,*\"\\"; - const uint8_t *p = valid; - while ((b = *p++)) if (b == c) return false; -#endif - // check size and only allow ASCII printable characters - if (i > n || c < 0X21 || c > 0X7E)return false; - // only upper case allowed in 8.3 names - convert lower to upper - name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); - } - } - // must have a file name, extension is optional - return name[0] != ' '; -} -//------------------------------------------------------------------------------ -/** Make a new directory. - * - * \param[in] dir An open SdFat instance for the directory that will containing - * the new directory. - * - * \param[in] dirName A valid 8.3 DOS name for the new directory. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include this SdFile is already open, \a dir is not a - * directory, \a dirName is invalid or already exists in \a dir. - */ -uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { - dir_t d; - - // create a normal file - if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false; - - // convert SdFile to directory - flags_ = O_READ; - type_ = FAT_FILE_TYPE_SUBDIR; - - // allocate and zero first cluster - if (!addDirCluster())return false; - - // force entry to SD - if (!sync()) return false; - - // cache entry - should already be in cache due to sync() call - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) return false; - - // change directory entry attribute - p->attributes = DIR_ATT_DIRECTORY; - - // make entry for '.' - memcpy(&d, p, sizeof(d)); - for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; - d.name[0] = '.'; - - // cache block for '.' and '..' - uint32_t block = vol_->clusterStartBlock(firstCluster_); - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; - - // copy '.' to block - memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); - - // make entry for '..' - d.name[1] = '.'; - if (dir->isRoot()) { - d.firstClusterLow = 0; - d.firstClusterHigh = 0; - } else { - d.firstClusterLow = dir->firstCluster_ & 0XFFFF; - d.firstClusterHigh = dir->firstCluster_ >> 16; - } - // copy '..' to block - memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); - - // set position after '..' - curPosition_ = 2 * sizeof(d); - - // write first block - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Open a file or directory by name. - * - * \param[in] dirFile An open SdFat instance for the directory containing the - * file to be opened. - * - * \param[in] fileName A valid 8.3 DOS name for a file to be opened. - * - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of flags from the following list - * - * O_READ - Open for reading. - * - * O_RDONLY - Same as O_READ. - * - * O_WRITE - Open for writing. - * - * O_WRONLY - Same as O_WRITE. - * - * O_RDWR - Open for reading and writing. - * - * O_APPEND - If set, the file offset shall be set to the end of the - * file prior to each write. - * - * O_CREAT - If the file exists, this flag has no effect except as noted - * under O_EXCL below. Otherwise, the file shall be created - * - * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. - * - * O_SYNC - Call sync() after each write. This flag should not be used with - * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. - * These functions do character at a time writes so sync() will be called - * after each byte. - * - * O_TRUNC - If the file exists and is a regular file, and the file is - * successfully opened and is not read only, its length shall be truncated to 0. - * - * \note Directory files must be opened read only. Write and truncation is - * not allowed for directory files. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include this SdFile is already open, \a difFile is not - * a directory, \a fileName is invalid, the file does not exist - * or can't be opened in the access mode specified by oflag. - */ -uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { - uint8_t dname[11]; - dir_t* p; - - // error if already open - if (isOpen())return false; - - if (!make83Name(fileName, dname)) return false; - vol_ = dirFile->vol_; - dirFile->rewind(); - - // bool for empty entry found - uint8_t emptyFound = false; - - // search for file - while (dirFile->curPosition_ < dirFile->fileSize_) { - uint8_t index = 0XF & (dirFile->curPosition_ >> 5); - p = dirFile->readDirCache(); - if (p == NULL) return false; - - if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { - // remember first empty slot - if (!emptyFound) { - emptyFound = true; - dirIndex_ = index; - dirBlock_ = SdVolume::cacheBlockNumber_; - } - // done if no entries follow - if (p->name[0] == DIR_NAME_FREE) break; - } else if (!memcmp(dname, p->name, 11)) { - // don't open existing file if O_CREAT and O_EXCL - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; - - // open found file - return openCachedEntry(0XF & index, oflag); - } - } - // only create file if O_CREAT and O_WRITE - if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; - - // cache found slot or add cluster if end of file - if (emptyFound) { - p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) return false; - } else { - if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false; - - // add and zero cluster for dirFile - first cluster is in cache for write - if (!dirFile->addDirCluster()) return false; - - // use first entry in cluster - dirIndex_ = 0; - p = SdVolume::cacheBuffer_.dir; - } - // initialize as empty file - memset(p, 0, sizeof(dir_t)); - memcpy(p->name, dname, 11); - - // set timestamps - if (dateTime_) { - // call user function - dateTime_(&p->creationDate, &p->creationTime); - } else { - // use default date/time - p->creationDate = FAT_DEFAULT_DATE; - p->creationTime = FAT_DEFAULT_TIME; - } - p->lastAccessDate = p->creationDate; - p->lastWriteDate = p->creationDate; - p->lastWriteTime = p->creationTime; - - // force write of entry to SD - if (!SdVolume::cacheFlush()) return false; - - // open entry in cache - return openCachedEntry(dirIndex_, oflag); -} -//------------------------------------------------------------------------------ -/** - * Open a file by index. - * - * \param[in] dirFile An open SdFat instance for the directory. - * - * \param[in] index The \a index of the directory entry for the file to be - * opened. The value for \a index is (directory file position)/32. - * - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. - * - * See open() by fileName for definition of flags and return values. - * - */ -uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { - // error if already open - if (isOpen())return false; - - // don't open existing file if O_CREAT and O_EXCL - user call error - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; - - vol_ = dirFile->vol_; - - // seek to location of entry - if (!dirFile->seekSet(32 * index)) return false; - - // read entry into cache - dir_t* p = dirFile->readDirCache(); - if (p == NULL) return false; - - // error if empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_FREE || - p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { - return false; - } - // open cached entry - return openCachedEntry(index & 0XF, oflag); -} -//------------------------------------------------------------------------------ -// open a cached directory entry. Assumes vol_ is initializes -uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { - // location of entry in cache - dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; - - // write or truncate is an error for a directory or read-only file - if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { - if (oflag & (O_WRITE | O_TRUNC)) return false; - } - // remember location of directory entry on SD - dirIndex_ = dirIndex; - dirBlock_ = SdVolume::cacheBlockNumber_; - - // copy first cluster number for directory fields - firstCluster_ = (uint32_t)p->firstClusterHigh << 16; - firstCluster_ |= p->firstClusterLow; - - // make sure it is a normal file or subdirectory - if (DIR_IS_FILE(p)) { - fileSize_ = p->fileSize; - type_ = FAT_FILE_TYPE_NORMAL; - } else if (DIR_IS_SUBDIR(p)) { - if (!vol_->chainSize(firstCluster_, &fileSize_)) return false; - type_ = FAT_FILE_TYPE_SUBDIR; - } else { - return false; - } - // save open flags for read/write - flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - - // truncate file to zero length if requested - if (oflag & O_TRUNC) return truncate(0); - return true; -} -//------------------------------------------------------------------------------ -/** - * Open a volume's root directory. - * - * \param[in] vol The FAT volume containing the root directory to be opened. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the FAT volume has not been initialized - * or it a FAT12 volume. - */ -uint8_t SdFile::openRoot(SdVolume* vol) { - // error if file is already open - if (isOpen()) return false; - - if (vol->fatType() == 16) { - type_ = FAT_FILE_TYPE_ROOT16; - firstCluster_ = 0; - fileSize_ = 32 * vol->rootDirEntryCount(); - } else if (vol->fatType() == 32) { - type_ = FAT_FILE_TYPE_ROOT32; - firstCluster_ = vol->rootDirStart(); - if (!vol->chainSize(firstCluster_, &fileSize_)) return false; - } else { - // volume is not initialized or FAT12 - return false; - } - vol_ = vol; - // read only - flags_ = O_READ; - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - - // root has no directory entry - dirBlock_ = 0; - dirIndex_ = 0; - return true; -} -//------------------------------------------------------------------------------ -/** %Print the name field of a directory entry in 8.3 format to Serial. - * - * \param[in] dir The directory structure containing the name. - * \param[in] width Blank fill name if length is less than \a width. - */ -void SdFile::printDirName(const dir_t& dir, uint8_t width) { - uint8_t w = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) { - Serial.print('.'); - w++; - } - Serial.write(dir.name[i]); - w++; - } - if (DIR_IS_SUBDIR(&dir)) { - Serial.print('/'); - w++; - } - while (w < width) { - Serial.print(' '); - w++; - } -} -//------------------------------------------------------------------------------ -/** %Print a directory date field to Serial. - * - * Format is yyyy-mm-dd. - * - * \param[in] fatDate The date field from a directory entry. - */ -void SdFile::printFatDate(uint16_t fatDate) { - Serial.print(FAT_YEAR(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_MONTH(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_DAY(fatDate)); -} -//------------------------------------------------------------------------------ -/** %Print a directory time field to Serial. - * - * Format is hh:mm:ss. - * - * \param[in] fatTime The time field from a directory entry. - */ -void SdFile::printFatTime(uint16_t fatTime) { - printTwoDigits(FAT_HOUR(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_MINUTE(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_SECOND(fatTime)); -} -//------------------------------------------------------------------------------ -/** %Print a value as two digits to Serial. - * - * \param[in] v Value to be printed, 0 <= \a v <= 99 - */ -void SdFile::printTwoDigits(uint8_t v) { - char str[3]; - str[0] = '0' + v/10; - str[1] = '0' + v % 10; - str[2] = 0; - Serial.print(str); -} -//------------------------------------------------------------------------------ -/** - * Read data from a file starting at the current position. - * - * \param[out] buf Pointer to the location that will receive the data. - * - * \param[in] nbyte Maximum number of bytes to read. - * - * \return For success read() returns the number of bytes read. - * A value less than \a nbyte, including zero, will be returned - * if end of file is reached. - * If an error occurs, read() returns -1. Possible errors include - * read() called before a file has been opened, corrupt file system - * or an I/O error occurred. - */ -int16_t SdFile::read(void* buf, uint16_t nbyte) { - uint8_t* dst = reinterpret_cast(buf); - - // error if not open or write only - if (!isOpen() || !(flags_ & O_READ)) return -1; - - // max bytes left in file - if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; - - // amount left to read - uint16_t toRead = nbyte; - while (toRead > 0) { - uint32_t block; // raw device block number - uint16_t offset = curPosition_ & 0X1FF; // offset in block - if (type_ == FAT_FILE_TYPE_ROOT16) { - block = vol_->rootDirStart() + (curPosition_ >> 9); - } else { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - if (offset == 0 && blockOfCluster == 0) { - // start of new cluster - if (curPosition_ == 0) { - // use first cluster in file - curCluster_ = firstCluster_; - } else { - // get next cluster from FAT - if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; - } - } - block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - } - uint16_t n = toRead; - - // amount to be read from current block - if (n > (512 - offset)) n = 512 - offset; - - // no buffering needed if n == 512 or user requests no buffering - if ((unbufferedRead() || n == 512) && - block != SdVolume::cacheBlockNumber_) { - if (!vol_->readData(block, offset, n, dst)) return -1; - dst += n; - } else { - // read block to cache and copy data to caller - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1; - uint8_t* src = SdVolume::cacheBuffer_.data + offset; - uint8_t* end = src + n; - while (src != end) *dst++ = *src++; - } - curPosition_ += n; - toRead -= n; - } - return nbyte; -} -//------------------------------------------------------------------------------ -/** - * Read the next directory entry from a directory file. - * - * \param[out] dir The dir_t struct that will receive the data. - * - * \return For success readDir() returns the number of bytes read. - * A value of zero will be returned if end of file is reached. - * If an error occurs, readDir() returns -1. Possible errors include - * readDir() called before a directory has been opened, this is not - * a directory file or an I/O error occurred. - */ -int8_t SdFile::readDir(dir_t* dir) { - int8_t n; - // if not a directory file or miss-positioned return an error - if (!isDir() || (0X1F & curPosition_)) return -1; - - while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { - // last entry if DIR_NAME_FREE - if (dir->name[0] == DIR_NAME_FREE) break; - // skip empty entries and entry for . and .. - if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; - // return if normal file or subdirectory - if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; - } - // error, end of file, or past last entry - return n < 0 ? -1 : 0; -} -//------------------------------------------------------------------------------ -// Read next directory entry into the cache -// Assumes file is correctly positioned -dir_t* SdFile::readDirCache(void) { - // error if not directory - if (!isDir()) return NULL; - - // index of entry in cache - uint8_t i = (curPosition_ >> 5) & 0XF; - - // use read to locate and cache block - if (read() < 0) return NULL; - - // advance to next entry - curPosition_ += 31; - - // return pointer to entry - return (SdVolume::cacheBuffer_.dir + i); -} -//------------------------------------------------------------------------------ -/** - * Remove a file. - * - * The directory entry and all data for the file are deleted. - * - * \note This function should not be used to delete the 8.3 version of a - * file that has a long name. For example if a file has the long name - * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file read-only, is a directory, - * or an I/O error occurred. - */ -uint8_t SdFile::remove(void) { - // free any clusters - will fail if read-only or directory - if (!truncate(0)) return false; - - // cache directory entry - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - // mark entry deleted - d->name[0] = DIR_NAME_DELETED; - - // set this SdFile closed - type_ = FAT_FILE_TYPE_CLOSED; - - // write entry to SD - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Remove a file. - * - * The directory entry and all data for the file are deleted. - * - * \param[in] dirFile The directory that contains the file. - * \param[in] fileName The name of the file to be removed. - * - * \note This function should not be used to delete the 8.3 version of a - * file that has a long name. For example if a file has the long name - * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file is a directory, is read only, - * \a dirFile is not a directory, \a fileName is not found - * or an I/O error occurred. - */ -uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { - SdFile file; - if (!file.open(dirFile, fileName, O_WRITE)) return false; - return file.remove(); -} -//------------------------------------------------------------------------------ -/** Remove a directory file. - * - * The directory file will be removed only if it is empty and is not the - * root directory. rmDir() follows DOS and Windows and ignores the - * read-only attribute for the directory. - * - * \note This function should not be used to delete the 8.3 version of a - * directory that has a long name. For example if a directory has the - * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include the file is not a directory, is the root - * directory, is not empty, or an I/O error occurred. - */ -uint8_t SdFile::rmDir(void) { - // must be open subdirectory - if (!isSubDir()) return false; - - rewind(); - - // make sure directory is empty - while (curPosition_ < fileSize_) { - dir_t* p = readDirCache(); - if (p == NULL) return false; - // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) break; - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - // error not empty - if (DIR_IS_FILE_OR_SUBDIR(p)) return false; - } - // convert empty directory to normal file for remove - type_ = FAT_FILE_TYPE_NORMAL; - flags_ |= O_WRITE; - return remove(); -} -//------------------------------------------------------------------------------ -/** Recursively delete a directory and all contained files. - * - * This is like the Unix/Linux 'rm -rf *' if called with the root directory - * hence the name. - * - * Warning - This will remove all contents of the directory including - * subdirectories. The directory will then be removed if it is not root. - * The read-only attribute for files will be ignored. - * - * \note This function should not be used to delete the 8.3 version of - * a directory that has a long name. See remove() and rmDir(). - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::rmRfStar(void) { - rewind(); - while (curPosition_ < fileSize_) { - SdFile f; - - // remember position - uint16_t index = curPosition_/32; - - dir_t* p = readDirCache(); - if (!p) return false; - - // done if past last entry - if (p->name[0] == DIR_NAME_FREE) break; - - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - - // skip if part of long file name or volume label in root - if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; - - if (!f.open(this, index, O_READ)) return false; - if (f.isSubDir()) { - // recursively delete - if (!f.rmRfStar()) return false; - } else { - // ignore read-only - f.flags_ |= O_WRITE; - if (!f.remove()) return false; - } - // position to next entry if required - if (curPosition_ != (32*(index + 1))) { - if (!seekSet(32*(index + 1))) return false; - } - } - // don't try to delete root - if (isRoot()) return true; - return rmDir(); -} -//------------------------------------------------------------------------------ -/** - * Sets a file's position. - * - * \param[in] pos The new position in bytes from the beginning of the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::seekSet(uint32_t pos) { - // error if file not open or seek past end of file - if (!isOpen() || pos > fileSize_) return false; - - if (type_ == FAT_FILE_TYPE_ROOT16) { - curPosition_ = pos; - return true; - } - if (pos == 0) { - // set position to start of file - curCluster_ = 0; - curPosition_ = 0; - return true; - } - // calculate cluster index for cur and new position - uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); - uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); - - if (nNew < nCur || curPosition_ == 0) { - // must follow chain from first cluster - curCluster_ = firstCluster_; - } else { - // advance from curPosition - nNew -= nCur; - } - while (nNew--) { - if (!vol_->fatGet(curCluster_, &curCluster_)) return false; - } - curPosition_ = pos; - return true; -} -//------------------------------------------------------------------------------ -/** - * The sync() call causes all modified data and directory fields - * to be written to the storage device. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include a call to sync() before a file has been - * opened or an I/O error. - */ -uint8_t SdFile::sync(void) { - // only allow open files and directories - if (!isOpen()) return false; - - if (flags_ & F_FILE_DIR_DIRTY) { - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - // do not set filesize for dir files - if (!isDir()) d->fileSize = fileSize_; - - // update first cluster fields - d->firstClusterLow = firstCluster_ & 0XFFFF; - d->firstClusterHigh = firstCluster_ >> 16; - - // set modify time if user supplied a callback date/time function - if (dateTime_) { - dateTime_(&d->lastWriteDate, &d->lastWriteTime); - d->lastAccessDate = d->lastWriteDate; - } - // clear directory dirty - flags_ &= ~F_FILE_DIR_DIRTY; - } - return SdVolume::cacheFlush(); -} -//------------------------------------------------------------------------------ -/** - * Set a file's timestamps in its directory entry. - * - * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive - * OR of flags from the following list - * - * T_ACCESS - Set the file's last access date. - * - * T_CREATE - Set the file's creation date and time. - * - * T_WRITE - Set the file's last write/modification date and time. - * - * \param[in] year Valid range 1980 - 2107 inclusive. - * - * \param[in] month Valid range 1 - 12 inclusive. - * - * \param[in] day Valid range 1 - 31 inclusive. - * - * \param[in] hour Valid range 0 - 23 inclusive. - * - * \param[in] minute Valid range 0 - 59 inclusive. - * - * \param[in] second Valid range 0 - 59 inclusive - * - * \note It is possible to set an invalid date since there is no check for - * the number of days in a month. - * - * \note - * Modify and access timestamps may be overwritten if a date time callback - * function has been set by dateTimeCallback(). - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ -uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, - uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { - if (!isOpen() - || year < 1980 - || year > 2107 - || month < 1 - || month > 12 - || day < 1 - || day > 31 - || hour > 23 - || minute > 59 - || second > 59) { - return false; - } - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) return false; - - uint16_t dirDate = FAT_DATE(year, month, day); - uint16_t dirTime = FAT_TIME(hour, minute, second); - if (flags & T_ACCESS) { - d->lastAccessDate = dirDate; - } - if (flags & T_CREATE) { - d->creationDate = dirDate; - d->creationTime = dirTime; - // seems to be units of 1/100 second not 1/10 as Microsoft states - d->creationTimeTenths = second & 1 ? 100 : 0; - } - if (flags & T_WRITE) { - d->lastWriteDate = dirDate; - d->lastWriteTime = dirTime; - } - SdVolume::cacheSetDirty(); - return sync(); -} -//------------------------------------------------------------------------------ -/** - * Truncate a file to a specified length. The current file position - * will be maintained if it is less than or equal to \a length otherwise - * it will be set to end of file. - * - * \param[in] length The desired length for the file. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - * Reasons for failure include file is read only, file is a directory, - * \a length is greater than the current file size or an I/O error occurs. - */ -uint8_t SdFile::truncate(uint32_t length) { -// error if not a normal file or read-only - if (!isFile() || !(flags_ & O_WRITE)) return false; - - // error if length is greater than current size - if (length > fileSize_) return false; - - // fileSize and length are zero - nothing to do - if (fileSize_ == 0) return true; - - // remember position for seek after truncation - uint32_t newPos = curPosition_ > length ? length : curPosition_; - - // position to last cluster in truncated file - if (!seekSet(length)) return false; - - if (length == 0) { - // free all clusters - if (!vol_->freeChain(firstCluster_)) return false; - firstCluster_ = 0; - } else { - uint32_t toFree; - if (!vol_->fatGet(curCluster_, &toFree)) return false; - - if (!vol_->isEOC(toFree)) { - // free extra clusters - if (!vol_->freeChain(toFree)) return false; - - // current cluster is end of chain - if (!vol_->fatPutEOC(curCluster_)) return false; - } - } - fileSize_ = length; - - // need to update directory entry - flags_ |= F_FILE_DIR_DIRTY; - - if (!sync()) return false; - - // set file to correct position - return seekSet(newPos); -} -//------------------------------------------------------------------------------ -/** - * Write data to an open file. - * - * \note Data is moved to the cache but may not be written to the - * storage device until sync() is called. - * - * \param[in] buf Pointer to the location of the data to be written. - * - * \param[in] nbyte Number of bytes to write. - * - * \return For success write() returns the number of bytes written, always - * \a nbyte. If an error occurs, write() returns -1. Possible errors - * include write() is called before a file has been opened, write is called - * for a read-only file, device is full, a corrupt file system or an I/O error. - * - */ -size_t SdFile::write(const void* buf, uint16_t nbyte) { - // convert void* to uint8_t* - must be before goto statements - const uint8_t* src = reinterpret_cast(buf); - - // number of bytes left to write - must be before goto statements - uint16_t nToWrite = nbyte; - - // error if not a normal file or is read-only - if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; - - // seek to end of file if append flag - if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { - if (!seekEnd()) goto writeErrorReturn; - } - - while (nToWrite > 0) { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - uint16_t blockOffset = curPosition_ & 0X1FF; - if (blockOfCluster == 0 && blockOffset == 0) { - // start of new cluster - if (curCluster_ == 0) { - if (firstCluster_ == 0) { - // allocate first cluster of file - if (!addCluster()) goto writeErrorReturn; - } else { - curCluster_ = firstCluster_; - } - } else { - uint32_t next; - if (!vol_->fatGet(curCluster_, &next)) return false; - if (vol_->isEOC(next)) { - // add cluster if at end of chain - if (!addCluster()) goto writeErrorReturn; - } else { - curCluster_ = next; - } - } - } - // max space in block - uint16_t n = 512 - blockOffset; - - // lesser of space and amount to write - if (n > nToWrite) n = nToWrite; - - // block for data write - uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - if (n == 512) { - // full block - don't need to use cache - // invalidate cache if block is in cache - if (SdVolume::cacheBlockNumber_ == block) { - SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; - } - if (!vol_->writeBlock(block, src)) goto writeErrorReturn; - src += 512; - } else { - if (blockOffset == 0 && curPosition_ >= fileSize_) { - // start of new block don't need to read into cache - if (!SdVolume::cacheFlush()) goto writeErrorReturn; - SdVolume::cacheBlockNumber_ = block; - SdVolume::cacheSetDirty(); - } else { - // rewrite part of block - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { - goto writeErrorReturn; - } - } - uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; - uint8_t* end = dst + n; - while (dst != end) *dst++ = *src++; - } - nToWrite -= n; - curPosition_ += n; - } - if (curPosition_ > fileSize_) { - // update fileSize and insure sync will update dir entry - fileSize_ = curPosition_; - flags_ |= F_FILE_DIR_DIRTY; - } else if (dateTime_ && nbyte) { - // insure sync will update modified date and time - flags_ |= F_FILE_DIR_DIRTY; - } - - if (flags_ & O_SYNC) { - if (!sync()) goto writeErrorReturn; - } - return nbyte; - - writeErrorReturn: - // return for write error - //writeError = true; - setWriteError(); - return 0; -} -//------------------------------------------------------------------------------ -/** - * Write a byte to a file. Required by the Arduino Print class. - * - * Use SdFile::writeError to check for errors. - */ -size_t SdFile::write(uint8_t b) { - return write(&b, 1); -} -//------------------------------------------------------------------------------ -/** - * Write a string to a file. Used by the Arduino Print class. - * - * Use SdFile::writeError to check for errors. - */ -size_t SdFile::write(const char* str) { - return write(str, strlen(str)); -} -#ifdef __AVR__ -//------------------------------------------------------------------------------ -/** - * Write a PROGMEM string to a file. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::write_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); -} -//------------------------------------------------------------------------------ -/** - * Write a PROGMEM string followed by CR/LF to a file. - * - * Use SdFile::writeError to check for errors. - */ -void SdFile::writeln_P(PGM_P str) { - write_P(str); - println(); -} -#endif diff --git a/libraries/SD/src/utility/SdInfo.h b/libraries/SD/src/utility/SdInfo.h deleted file mode 100644 index bc4c6137..00000000 --- a/libraries/SD/src/utility/SdInfo.h +++ /dev/null @@ -1,232 +0,0 @@ -/* Arduino Sd2Card Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino Sd2Card 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 Sd2Card Library. If not, see - * . - */ -#ifndef SdInfo_h -#define SdInfo_h -#include -// 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 -//------------------------------------------------------------------------------ -// SD card commands -/** GO_IDLE_STATE - init card in spi mode if CS low */ -uint8_t const CMD0 = 0X00; -/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ -uint8_t const CMD8 = 0X08; -/** SEND_CSD - read the Card Specific Data (CSD register) */ -uint8_t const CMD9 = 0X09; -/** SEND_CID - read the card identification information (CID register) */ -uint8_t const CMD10 = 0X0A; -/** SEND_STATUS - read the card status register */ -uint8_t const CMD13 = 0X0D; -/** READ_BLOCK - read a single data block from the card */ -uint8_t const CMD17 = 0X11; -/** WRITE_BLOCK - write a single data block to the card */ -uint8_t const CMD24 = 0X18; -/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ -uint8_t const CMD25 = 0X19; -/** ERASE_WR_BLK_START - sets the address of the first block to be erased */ -uint8_t const CMD32 = 0X20; -/** ERASE_WR_BLK_END - sets the address of the last block of the continuous - range to be erased*/ -uint8_t const CMD33 = 0X21; -/** ERASE - erase all previously selected blocks */ -uint8_t const CMD38 = 0X26; -/** APP_CMD - escape for application specific command */ -uint8_t const CMD55 = 0X37; -/** READ_OCR - read the OCR register of a card */ -uint8_t const CMD58 = 0X3A; -/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be - pre-erased before writing */ -uint8_t const ACMD23 = 0X17; -/** SD_SEND_OP_COMD - Sends host capacity support information and - activates the card's initialization process */ -uint8_t const ACMD41 = 0X29; -//------------------------------------------------------------------------------ -/** status for card in the ready state */ -uint8_t const R1_READY_STATE = 0X00; -/** status for card in the idle state */ -uint8_t const R1_IDLE_STATE = 0X01; -/** status bit for illegal command */ -uint8_t const R1_ILLEGAL_COMMAND = 0X04; -/** start data token for read or write single block*/ -uint8_t const DATA_START_BLOCK = 0XFE; -/** stop token for write multiple blocks*/ -uint8_t const STOP_TRAN_TOKEN = 0XFD; -/** start data token for write multiple blocks*/ -uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC; -/** mask for data response tokens after a write block operation */ -uint8_t const DATA_RES_MASK = 0X1F; -/** write data accepted token */ -uint8_t const DATA_RES_ACCEPTED = 0X05; -//------------------------------------------------------------------------------ -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; -//------------------------------------------------------------------------------ -// CSD for version 1.00 cards -typedef struct CSDV1 { - // 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; -}csd1_t; -//------------------------------------------------------------------------------ -// CSD for version 2.00 cards -typedef struct CSDV2 { - // 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 reserved2 : 4; - unsigned dsr_imp : 1; - unsigned read_blk_misalign :1; - unsigned write_blk_misalign : 1; - unsigned read_bl_partial : 1; - // byte 7 - unsigned reserved3 : 2; - unsigned c_size_high : 6; - // byte 8 - uint8_t c_size_mid; - // byte 9 - uint8_t c_size_low; - // byte 10 - unsigned sector_size_high : 6; - unsigned erase_blk_en : 1; - unsigned reserved4 : 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 reserved5 : 2; - unsigned wp_grp_enable : 1; - // byte 13 - unsigned reserved6 : 5; - unsigned write_partial : 1; - unsigned write_bl_len_low : 2; - // byte 14 - unsigned reserved7: 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; -}csd2_t; -//------------------------------------------------------------------------------ -// union of old and new style CSD register -union csd_t { - csd1_t v1; - csd2_t v2; -}; -#endif // SdInfo_h diff --git a/libraries/SD/src/utility/SdVolume.cpp b/libraries/SD/src/utility/SdVolume.cpp deleted file mode 100644 index 3c1e641c..00000000 --- a/libraries/SD/src/utility/SdVolume.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* Arduino SdFat Library - * Copyright (C) 2009 by William Greiman - * - * This file is part of the Arduino SdFat 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 SdFat Library. If not, see - * . - */ -#include "SdFat.h" -//------------------------------------------------------------------------------ -// raw block cache -// init cacheBlockNumber_to invalid SD block number -uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; -cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card -Sd2Card* SdVolume::sdCard_; // pointer to SD card object -uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true -uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT -//------------------------------------------------------------------------------ -// find a contiguous group of clusters -uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { - // start of group - uint32_t bgnCluster; - - // flag to save place to start next search - uint8_t setStart; - - // set search start cluster - if (*curCluster) { - // try to make file contiguous - bgnCluster = *curCluster + 1; - - // don't save new start location - setStart = false; - } else { - // start at likely place for free cluster - bgnCluster = allocSearchStart_; - - // save next search start if one cluster - setStart = 1 == count; - } - // end of group - uint32_t endCluster = bgnCluster; - - // last cluster of FAT - uint32_t fatEnd = clusterCount_ + 1; - - // search the FAT for free clusters - for (uint32_t n = 0;; n++, endCluster++) { - // can't find space checked all clusters - if (n >= clusterCount_) return false; - - // past end - start from beginning of FAT - if (endCluster > fatEnd) { - bgnCluster = endCluster = 2; - } - uint32_t f; - if (!fatGet(endCluster, &f)) return false; - - if (f != 0) { - // cluster in use try next cluster as bgnCluster - bgnCluster = endCluster + 1; - } else if ((endCluster - bgnCluster + 1) == count) { - // done - found space - break; - } - } - // mark end of chain - if (!fatPutEOC(endCluster)) return false; - - // link clusters - while (endCluster > bgnCluster) { - if (!fatPut(endCluster - 1, endCluster)) return false; - endCluster--; - } - if (*curCluster != 0) { - // connect chains - if (!fatPut(*curCluster, bgnCluster)) return false; - } - // return first cluster number to caller - *curCluster = bgnCluster; - - // remember possible next free cluster - if (setStart) allocSearchStart_ = bgnCluster + 1; - - return true; -} -//------------------------------------------------------------------------------ -uint8_t SdVolume::cacheFlush(void) { - if (cacheDirty_) { - if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { - return false; - } - // mirror FAT tables - if (cacheMirrorBlock_) { - if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { - return false; - } - cacheMirrorBlock_ = 0; - } - cacheDirty_ = 0; - } - return true; -} -//------------------------------------------------------------------------------ -uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) { - if (cacheBlockNumber_ != blockNumber) { - if (!cacheFlush()) return false; - if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false; - cacheBlockNumber_ = blockNumber; - } - cacheDirty_ |= action; - return true; -} -//------------------------------------------------------------------------------ -// cache a zero block for blockNumber -uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) { - if (!cacheFlush()) return false; - - // loop take less flash than memset(cacheBuffer_.data, 0, 512); - for (uint16_t i = 0; i < 512; i++) { - cacheBuffer_.data[i] = 0; - } - cacheBlockNumber_ = blockNumber; - cacheSetDirty(); - return true; -} -//------------------------------------------------------------------------------ -// return the size in bytes of a cluster chain -uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const { - uint32_t s = 0; - do { - if (!fatGet(cluster, &cluster)) return false; - s += 512UL << clusterSizeShift_; - } while (!isEOC(cluster)); - *size = s; - return true; -} -//------------------------------------------------------------------------------ -// Fetch a FAT entry -uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const { - if (cluster > (clusterCount_ + 1)) return false; - uint32_t lba = fatStartBlock_; - lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; - if (lba != cacheBlockNumber_) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; - } - if (fatType_ == 16) { - *value = cacheBuffer_.fat16[cluster & 0XFF]; - } else { - *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; - } - return true; -} -//------------------------------------------------------------------------------ -// Store a FAT entry -uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) { - // error if reserved cluster - if (cluster < 2) return false; - - // error if not in FAT - if (cluster > (clusterCount_ + 1)) return false; - - // calculate block address for entry - uint32_t lba = fatStartBlock_; - lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; - - if (lba != cacheBlockNumber_) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; - } - // store entry - if (fatType_ == 16) { - cacheBuffer_.fat16[cluster & 0XFF] = value; - } else { - cacheBuffer_.fat32[cluster & 0X7F] = value; - } - cacheSetDirty(); - - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - return true; -} -//------------------------------------------------------------------------------ -// free a cluster chain -uint8_t SdVolume::freeChain(uint32_t cluster) { - // clear free cluster location - allocSearchStart_ = 2; - - do { - uint32_t next; - if (!fatGet(cluster, &next)) return false; - - // free cluster - if (!fatPut(cluster, 0)) return false; - - cluster = next; - } while (!isEOC(cluster)); - - return true; -} -//------------------------------------------------------------------------------ -/** - * Initialize a FAT volume. - * - * \param[in] dev The SD card where the volume is located. - * - * \param[in] part The partition to be used. Legal values for \a part are - * 1-4 to use the corresponding partition on a device formatted with - * a MBR, Master Boot Record, or zero if the device is formatted as - * a super floppy with the FAT boot sector in block zero. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. Reasons for - * failure include not finding a valid partition, not finding a valid - * FAT file system in the specified partition or an I/O error. - */ -uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) { - uint32_t volumeStartBlock = 0; - sdCard_ = dev; - // if part == 0 assume super floppy with FAT boot sector in block zero - // if part > 0 assume mbr volume with partition table - if (part) { - if (part > 4)return false; - if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; - part_t* p = &cacheBuffer_.mbr.part[part-1]; - if ((p->boot & 0X7F) !=0 || - p->totalSectors < 100 || - p->firstSector == 0) { - // not a valid partition - return false; - } - volumeStartBlock = p->firstSector; - } - if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; - bpb_t* bpb = &cacheBuffer_.fbs.bpb; - if (bpb->bytesPerSector != 512 || - bpb->fatCount == 0 || - bpb->reservedSectorCount == 0 || - bpb->sectorsPerCluster == 0) { - // not valid FAT volume - return false; - } - fatCount_ = bpb->fatCount; - blocksPerCluster_ = bpb->sectorsPerCluster; - - // determine shift that is same as multiply by blocksPerCluster_ - clusterSizeShift_ = 0; - while (blocksPerCluster_ != (1 << clusterSizeShift_)) { - // error if not power of 2 - if (clusterSizeShift_++ > 7) return false; - } - blocksPerFat_ = bpb->sectorsPerFat16 ? - bpb->sectorsPerFat16 : bpb->sectorsPerFat32; - - fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount; - - // count for FAT16 zero for FAT32 - rootDirEntryCount_ = bpb->rootDirEntryCount; - - // directory start for FAT16 dataStart for FAT32 - rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_; - - // data start for FAT16 and FAT32 - dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512); - - // total blocks for FAT16 or FAT32 - uint32_t totalBlocks = bpb->totalSectors16 ? - bpb->totalSectors16 : bpb->totalSectors32; - // total data blocks - clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); - - // divide by cluster size to get cluster count - clusterCount_ >>= clusterSizeShift_; - - // FAT type is determined by cluster count - if (clusterCount_ < 4085) { - fatType_ = 12; - } else if (clusterCount_ < 65525) { - fatType_ = 16; - } else { - rootDirStart_ = bpb->fat32RootCluster; - fatType_ = 32; - } - return true; -} From 4cad8b8e31d7e8f13b394e90ffa2253ffb0d5f9b Mon Sep 17 00:00:00 2001 From: russmcinnis Date: Wed, 6 Apr 2016 13:30:42 -0600 Subject: [PATCH 024/222] pwmStop() leaves pin HIGH pwmStop() was doing a digitalWrite(pwmPin, LOW) after the kill() so unless the pin happened to be 0 the pwmPin might be left in the HIGH state causing motors or other devices to run HIGH after pwmStop(). Just removed the pwmPin = 0 from kill() and it passes all our loopback tests. --- libraries/CurieTimerOne/src/CurieTimerOne.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/CurieTimerOne/src/CurieTimerOne.cpp b/libraries/CurieTimerOne/src/CurieTimerOne.cpp index 5aa76385..9758a3d8 100644 --- a/libraries/CurieTimerOne/src/CurieTimerOne.cpp +++ b/libraries/CurieTimerOne/src/CurieTimerOne.cpp @@ -76,7 +76,7 @@ void CurieTimer::kill() tickCnt = 0; userCB = NULL; currState = IDLE; - pauseCntrl = pauseCount = pwmPin = dutyCycle = nonDutyCycle = periodInUsec = 0; + pauseCntrl = pauseCount = dutyCycle = nonDutyCycle = periodInUsec = 0; } From e9aaea9b39eb1496ebccdef422ae2d441f9086f4 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Fri, 8 Apr 2016 15:11:42 -0600 Subject: [PATCH 025/222] Fix CurieTimerOne example filename Signed-off-by: Brian Baltz --- .../{blinkSpeed.ino => CurieTimer1BlinkSpeed.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/{blinkSpeed.ino => CurieTimer1BlinkSpeed.ino} (100%) diff --git a/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino b/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/CurieTimer1BlinkSpeed.ino similarity index 100% rename from libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino rename to libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/CurieTimer1BlinkSpeed.ino From 285ec1770d831f584ca943f2e4d214ad59e35ffe Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Tue, 12 Apr 2016 10:56:38 -0600 Subject: [PATCH 026/222] Removing obsolete TFT library Signed-off-by: Brian Baltz --- libraries/TFT/README.adoc | 26 - .../Arduino/TFTBitmapLogo/TFTBitmapLogo.ino | 108 --- .../Arduino/TFTBitmapLogo/arduino.bmp | Bin 6966 -> 0 bytes .../Arduino/TFTColorPicker/TFTColorPicker.ino | 67 -- .../Arduino/TFTDisplayText/TFTDisplayText.ino | 74 -- .../Arduino/TFTEtchASketch/TFTEtchASketch.ino | 84 -- .../examples/Arduino/TFTGraph/TFTGraph.ino | 71 -- .../TFT/examples/Arduino/TFTPong/TFTPong.ino | 135 ---- libraries/TFT/extras/Adafruit-README.txt | 21 - libraries/TFT/extras/Adafruit-license.txt | 25 - libraries/TFT/extras/README.md | 18 - libraries/TFT/keywords.txt | 20 - libraries/TFT/library.properties | 9 - libraries/TFT/src/TFT.cpp | 51 -- libraries/TFT/src/TFT.h | 58 -- libraries/TFT/src/utility/Adafruit_GFX.cpp | 715 ----------------- libraries/TFT/src/utility/Adafruit_GFX.h | 372 --------- libraries/TFT/src/utility/Adafruit_ST7735.cpp | 751 ------------------ libraries/TFT/src/utility/Adafruit_ST7735.h | 155 ---- libraries/TFT/src/utility/PImage.h | 65 -- libraries/TFT/src/utility/glcdfont.c | 268 ------- libraries/TFT/src/utility/keywords.txt | 70 -- 22 files changed, 3163 deletions(-) delete mode 100644 libraries/TFT/README.adoc delete mode 100644 libraries/TFT/examples/Arduino/TFTBitmapLogo/TFTBitmapLogo.ino delete mode 100644 libraries/TFT/examples/Arduino/TFTBitmapLogo/arduino.bmp delete mode 100644 libraries/TFT/examples/Arduino/TFTColorPicker/TFTColorPicker.ino delete mode 100644 libraries/TFT/examples/Arduino/TFTDisplayText/TFTDisplayText.ino delete mode 100644 libraries/TFT/examples/Arduino/TFTEtchASketch/TFTEtchASketch.ino delete mode 100644 libraries/TFT/examples/Arduino/TFTGraph/TFTGraph.ino delete mode 100644 libraries/TFT/examples/Arduino/TFTPong/TFTPong.ino delete mode 100644 libraries/TFT/extras/Adafruit-README.txt delete mode 100644 libraries/TFT/extras/Adafruit-license.txt delete mode 100644 libraries/TFT/extras/README.md delete mode 100644 libraries/TFT/keywords.txt delete mode 100644 libraries/TFT/library.properties delete mode 100644 libraries/TFT/src/TFT.cpp delete mode 100644 libraries/TFT/src/TFT.h delete mode 100644 libraries/TFT/src/utility/Adafruit_GFX.cpp delete mode 100644 libraries/TFT/src/utility/Adafruit_GFX.h delete mode 100644 libraries/TFT/src/utility/Adafruit_ST7735.cpp delete mode 100644 libraries/TFT/src/utility/Adafruit_ST7735.h delete mode 100644 libraries/TFT/src/utility/PImage.h delete mode 100644 libraries/TFT/src/utility/glcdfont.c delete mode 100644 libraries/TFT/src/utility/keywords.txt diff --git a/libraries/TFT/README.adoc b/libraries/TFT/README.adoc deleted file mode 100644 index 0550e2d3..00000000 --- a/libraries/TFT/README.adoc +++ /dev/null @@ -1,26 +0,0 @@ -= TFT Library for Arduino = - -This library enables an Arduino board to communicate with the Arduino TFT LCD screen. It simplifies the process for drawing shapes, lines, images, and text to the screen. - -For more information about this library please visit us at -http://www.arduino.cc/en/Reference/TFTLibrary - -== License == - -Copyright (c) Arduino LLC. All right reserved. -Copyright (c) Enrico Gueli. All right reserved. -Copyright (c) 2012, Adafruit Industries. All rights reserved. - -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 St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/libraries/TFT/examples/Arduino/TFTBitmapLogo/TFTBitmapLogo.ino b/libraries/TFT/examples/Arduino/TFTBitmapLogo/TFTBitmapLogo.ino deleted file mode 100644 index 92459931..00000000 --- a/libraries/TFT/examples/Arduino/TFTBitmapLogo/TFTBitmapLogo.ino +++ /dev/null @@ -1,108 +0,0 @@ -/* - - Arduino TFT Bitmap Logo example - - This example reads an image file from a micro-SD card - and draws it on the screen, at random locations. - - In this sketch, the Arduino logo is read from a micro-SD card. - There is a .bmp file included with this sketch. - - open the sketch folder (Ctrl-K or Cmd-K) - - copy the "arduino.bmp" file to a micro-SD - - put the SD into the SD slot of the Arduino TFT module. - - This example code is in the public domain. - - Created 19 April 2013 by Enrico Gueli - - http://www.arduino.cc/en/Tutorial/TFTBitmapLogo - - */ - -// include the necessary libraries -#include -#include -#include // Arduino LCD library - -// pin definition for the Uno -#define sd_cs 4 -#define lcd_cs 10 -#define dc 9 -#define rst 8 - -// pin definition for the Leonardo -//#define sd_cs 8 -//#define lcd_cs 7 -//#define dc 0 -//#define rst 1 - -TFT TFTscreen = TFT(lcd_cs, dc, rst); - -// this variable represents the image to be drawn on screen -PImage logo; - - -void setup() { - // initialize the GLCD and show a message - // asking the user to open the serial line - TFTscreen.begin(); - TFTscreen.background(255, 255, 255); - - TFTscreen.stroke(0, 0, 255); - TFTscreen.println(); - TFTscreen.println(F("Arduino TFT Bitmap Example")); - TFTscreen.stroke(0, 0, 0); - TFTscreen.println(F("Open serial monitor")); - TFTscreen.println(F("to run the sketch")); - - // initialize the serial port: it will be used to - // print some diagnostic info - Serial.begin(9600); - while (!Serial) { - // wait for serial line to be ready - } - - // clear the GLCD screen before starting - TFTscreen.background(255, 255, 255); - - // try to access the SD card. If that fails (e.g. - // no card present), the setup process will stop. - Serial.print(F("Initializing SD card...")); - if (!SD.begin(sd_cs)) { - Serial.println(F("failed!")); - return; - } - Serial.println(F("OK!")); - - // initialize and clear the GLCD screen - TFTscreen.begin(); - TFTscreen.background(255, 255, 255); - - // now that the SD card can be access, try to load the - // image file. - logo = TFTscreen.loadImage("arduino.bmp"); - if (!logo.isValid()) { - Serial.println(F("error while loading arduino.bmp")); - } -} - -void loop() { - // don't do anything if the image wasn't loaded correctly. - if (logo.isValid() == false) { - return; - } - - Serial.println(F("drawing image")); - - // get a random location where to draw the image. - // To avoid the image to be draw outside the screen, - // take into account the image size. - int x = random(TFTscreen.width() - logo.width()); - int y = random(TFTscreen.height() - logo.height()); - - // draw the image to the screen - TFTscreen.image(logo, x, y); - - // wait a little bit before drawing again - delay(1500); -} diff --git a/libraries/TFT/examples/Arduino/TFTBitmapLogo/arduino.bmp b/libraries/TFT/examples/Arduino/TFTBitmapLogo/arduino.bmp deleted file mode 100644 index 09c670ab54f01647cd59b35a5b00ab381fcbe2ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6966 zcmeI0cWm256vv&UfM_Y3Quf}fVwAl%Vj~c=OtBF|Vu+0x5osrBbsX2#ndxUb(${o^pV!eL0cX_iF(IL+J1;Eg zTwmkiNC*u)i-S-*F6u@oz5Y0u{b2voP+(WdSAo7K4iDA!b{7Qr90v=Mn;Jp`eU3*O zWQno2Tdi$EB{cE&JS5ov)QFIa5Rw#s_w@AWj?^uIz9;Oi{58OPBl6klY)|KHUiKRp z4kZVT3^x`Rd|>i8u%_A*8-0w2bP%(3)W#7EzZ?U+!$>syFn5&Dde_e6$V91(J1M(UGBy<0`u5A5$q-D+@mL3y4r zk=Klkb;5`~<-5M)ZDHQKsDUqXvtIQv96DgBuv*)L{Z7FO;YU1c@;Iopx^J5~fPTl@UNWkerpZMsT(5JgAhmasbge{!j z+!RRw1b80{0j^;`J>`iYzmqNfWx!={*OiriBlIaQ{K#Udh~0J_n&S&6e70&S&{13C z1%MbhI?}?4JBvOuy6Zr!uEr-X`*n~UuvEs!+=Am+)KnXc`Zc8`UkY$|5?x_I=Wwpr zL?7WVRILuB)d&#Ya3o828dn| zCSlp6P*hjBlT!pOlyJ>VTkC6mVMJP0#m{5}s`mC2veVbM6Bg_uH>amZ$bHyB9x^QA z)#~5BLjd;yGQbjk0A5}BTSHwSrH{%WQ(%82<9CX4Z%{ z^b|VCKD46CWM{mfrH0O^U;cwwf3IUGO0=+*M2%THsN0lx&5)Jk=*YhGl*dd%Z)0L5OZrr+EdiV zxTqWGeGaG4edx2Y$Rm?BL9tTh2s|mvX~~aeq&-dFq#{w!Ob=5xBch z*r_wLWBf}16ATn>3TavC*P(%Dt6rd_w=``NqG-6bv+RzhZ(>nN;m7@bJ1K)y8$>bH zj0`tX!8BhiVHg>@iD(gWwBot=3ItLTA7rGF+Bz%-2loIMy+EEzZ~`yG4>IK@@xMLc zUK)yuo+^qI%S?ZUI2SB9j+i7(kWZ(Oa+2ciqLr(R&g$2l zOZqeNsryVy%pP_|7seRu5?^^{?RcJ0QR(-wM)LOfdnB)1L`PmlPj_Ifuk$y$yAZd- z!wn9v=*to!a+WdAE@}-8R}#}bNyEKAadde#9srXg?Cdsh=>BT*LJSM@B!-JbW3=F_ zsxV)vkU|Kv1l4bGZCFo(kowRmh!E2s2g;8@@0y%=ALEUrVZop!tz&^x$RkMrF)Uh@ zSYyy@J|)vV4xo2P8iogwbkQhxSFM=aOk;#r^=YgRg3RB0gZyASfuZVy`P5;l4-*%S zMr|b!!@_t&uQBRfj2>>R5m>v&sOVEE^}%GNVz_bjkYrPngN)n`pOKMf)nD9eNP$Ju zv|z?Mb4#og0x>KD1G_0)pu`|Y&jJuN+Sy?Y7D8~Aj7iED!@r8Q6uaz#vcSN(1dhE7 zMulJD+}em|^jS8Zwa{8@QZ!%cu&mzT#^AT?=?|qV(cA^ z%`44s(9>Zdv!AOg%zH;vKc+qmBs=6QnkHj5VB!}BIno52sj)OiuCdZ0=qd69q)=YF zQk^Y?@Pv#Ji11(n0aAnzob=_vfjtBX*H7tUj>Z->>S)1Sfu%~CG*@zmdluI>0Ev#+ zY`d$Hv-Y@Ufo{!>5o*S9N5lK7!mv;%=;q0Z4-i+jxyAQH*=U3`LI_3&kAN*x%975? zxvCCg4H&pJz`eQ^Wt=X_II0?`va?1Ln-}um z;|l4ljMyOnm|?i+?ZY~bpgT}u7*yZ_AMWht=B3&tL{VKCT=R3@L~ZD8bGW7h0}rJ& zI^s(1%UmS?w(VjsNx^M5cH6ZW2)o_a+zZz8OAfz;bhM>%eGupJ(*)IkNE2Tjo=C$+ z-ZnLcaYNza$qaEcG // Arduino LCD library -#include - -TFT TFTscreen = TFT(cs, dc, rst); - -void setup() { - // begin serial communication - Serial.begin(9600); - - // initialize the display - TFTscreen.begin(); - - // set the background to white - TFTscreen.background(255, 255, 255); - -} - -void loop() { - - // read the values from your sensors and scale them to 0-255 - int redVal = map(analogRead(A0), 0, 1023, 0, 255); - int greenVal = map(analogRead(A1), 0, 1023, 0, 255); - int blueVal = map(analogRead(A2), 0, 1023, 0, 255); - - // draw the background based on the mapped values - TFTscreen.background(redVal, greenVal, blueVal); - - // send the values to the serial monitor - Serial.print("background("); - Serial.print(redVal); - Serial.print(" , "); - Serial.print(greenVal); - Serial.print(" , "); - Serial.print(blueVal); - Serial.println(")"); - - // wait for a moment - delay(33); - -} - diff --git a/libraries/TFT/examples/Arduino/TFTDisplayText/TFTDisplayText.ino b/libraries/TFT/examples/Arduino/TFTDisplayText/TFTDisplayText.ino deleted file mode 100644 index e09a976e..00000000 --- a/libraries/TFT/examples/Arduino/TFTDisplayText/TFTDisplayText.ino +++ /dev/null @@ -1,74 +0,0 @@ -/* - Arduino TFT text example - - This example demonstrates how to draw text on the - TFT with an Arduino. The Arduino reads the value - of an analog sensor attached to pin A0, and writes - the value to the LCD screen, updating every - quarter second. - - This example code is in the public domain - - Created 15 April 2013 by Scott Fitzgerald - - http://www.arduino.cc/en/Tutorial/TFTDisplayText - - */ - -#include // Arduino LCD library -#include - -// pin definition for the Uno -#define cs 10 -#define dc 9 -#define rst 8 - -// pin definition for the Leonardo -// #define cs 7 -// #define dc 0 -// #define rst 1 - -// create an instance of the library -TFT TFTscreen = TFT(cs, dc, rst); - -// char array to print to the screen -char sensorPrintout[4]; - -void setup() { - - // Put this line at the beginning of every sketch that uses the GLCD: - TFTscreen.begin(); - - // clear the screen with a black background - TFTscreen.background(0, 0, 0); - - // write the static text to the screen - // set the font color to white - TFTscreen.stroke(255, 255, 255); - // set the font size - TFTscreen.setTextSize(2); - // write the text to the top left corner of the screen - TFTscreen.text("Sensor Value :\n ", 0, 0); - // ste the font size very large for the loop - TFTscreen.setTextSize(5); -} - -void loop() { - - // Read the value of the sensor on A0 - String sensorVal = String(analogRead(A0)/2); - - // convert the reading to a char array - sensorVal.toCharArray(sensorPrintout, 4); - - // set the font color - TFTscreen.stroke(255, 255, 255); - // print the sensor value - TFTscreen.text(sensorPrintout, 0, 20); - // wait for a moment - delay(250); - // erase the text you just wrote - TFTscreen.stroke(0, 0, 0); - TFTscreen.text(sensorPrintout, 0, 20); -} - diff --git a/libraries/TFT/examples/Arduino/TFTEtchASketch/TFTEtchASketch.ino b/libraries/TFT/examples/Arduino/TFTEtchASketch/TFTEtchASketch.ino deleted file mode 100644 index 2a3d6e71..00000000 --- a/libraries/TFT/examples/Arduino/TFTEtchASketch/TFTEtchASketch.ino +++ /dev/null @@ -1,84 +0,0 @@ -/* - - TFT EtchASketch - - This example for the Arduino screen draws a white point - on the GLCD based on the values of 2 potentiometers. - To clear the screen, press a button attached to pin 2. - - This example code is in the public domain. - - Created 15 April 2013 by Scott Fitzgerald - - http://www.arduino.cc/en/Tutorial/TFTEtchASketch - - */ - -#include // Arduino LCD library -#include - -// pin definition for the Uno -#define cs 10 -#define dc 9 -#define rst 8 - -// pin definition for the Leonardo -// #define cs 7 -// #define dc 0 -// #define rst 1 - -TFT TFTscreen = TFT(cs, dc, rst); - -// initial position of the cursor -int xPos = TFTscreen.width() / 2; -int yPos = TFTscreen.height() / 2; - -// pin the erase switch is connected to -int erasePin = 2; - -void setup() { - // declare inputs - pinMode(erasePin, INPUT); - // initialize the screen - TFTscreen.begin(); - // make the background black - TFTscreen.background(0, 0, 0); -} - -void loop() -{ - // read the potentiometers on A0 and A1 - int xValue = analogRead(A0); - int yValue = analogRead(A1); - - // map the values and update the position - xPos = xPos + (map(xValue, 0, 1023, 2, -2)); - yPos = yPos + (map(yValue, 0, 1023, -2, 2)); - - // don't let the point go past the screen edges - if (xPos > 159) { - (xPos = 159); - } - - if (xPos < 0) { - (xPos = 0); - } - if (yPos > 127) { - (yPos = 127); - } - - if (yPos < 0) { - (yPos = 0); - } - - // draw the point - TFTscreen.stroke(255, 255, 255); - TFTscreen.point(xPos, yPos); - - // read the value of the pin, and erase the screen if pressed - if (digitalRead(erasePin) == HIGH) { - TFTscreen.background(0, 0, 0); - } - - delay(33); -} diff --git a/libraries/TFT/examples/Arduino/TFTGraph/TFTGraph.ino b/libraries/TFT/examples/Arduino/TFTGraph/TFTGraph.ino deleted file mode 100644 index 6c789593..00000000 --- a/libraries/TFT/examples/Arduino/TFTGraph/TFTGraph.ino +++ /dev/null @@ -1,71 +0,0 @@ -/* - - TFT Graph - - This example for an Arduino screen reads - the value of an analog sensor on A0, and - graphs the values on the screen. - - This example code is in the public domain. - - Created 15 April 2013 by Scott Fitzgerald - - http://www.arduino.cc/en/Tutorial/TFTGraph - - */ - -#include // Arduino LCD library -#include - -// pin definition for the Uno -#define cs 10 -#define dc 9 -#define rst 8 - -// pin definition for the Leonardo -// #define cs 7 -// #define dc 0 -// #define rst 1 - -TFT TFTscreen = TFT(cs, dc, rst); - -// position of the line on screen -int xPos = 0; - -void setup() { - // initialize the serial port - Serial.begin(9600); - - // initialize the display - TFTscreen.begin(); - - // clear the screen with a pretty color - TFTscreen.background(250, 16, 200); -} - -void loop() { - // read the sensor and map it to the screen height - int sensor = analogRead(A0); - int drawHeight = map(sensor, 0, 1023, 0, TFTscreen.height()); - - // print out the height to the serial monitor - Serial.println(drawHeight); - - // draw a line in a nice color - TFTscreen.stroke(250, 180, 10); - TFTscreen.line(xPos, TFTscreen.height() - drawHeight, xPos, TFTscreen.height()); - - // if the graph has reached the screen edge - // erase the screen and start again - if (xPos >= 160) { - xPos = 0; - TFTscreen.background(250, 16, 200); - } - else { - // increment the horizontal position: - xPos++; - } - - delay(16); -} - diff --git a/libraries/TFT/examples/Arduino/TFTPong/TFTPong.ino b/libraries/TFT/examples/Arduino/TFTPong/TFTPong.ino deleted file mode 100644 index 7a619153..00000000 --- a/libraries/TFT/examples/Arduino/TFTPong/TFTPong.ino +++ /dev/null @@ -1,135 +0,0 @@ -/* - - TFT Pong - - This example for the Arduino screen reads the values - of 2 potentiometers to move a rectangular platform - on the x and y axes. The platform can intersect - with a ball causing it to bounce. - - This example code is in the public domain. - - Created by Tom Igoe December 2012 - Modified 15 April 2013 by Scott Fitzgerald - - http://www.arduino.cc/en/Tutorial/TFTPong - - */ - -#include // Arduino LCD library -#include - -// pin definition for the Uno -#define cs 10 -#define dc 9 -#define rst 8 - -// pin definition for the Leonardo -// #define cs 7 -// #define dc 0 -// #define rst 1 - -TFT TFTscreen = TFT(cs, dc, rst); - -// variables for the position of the ball and paddle -int paddleX = 0; -int paddleY = 0; -int oldPaddleX, oldPaddleY; -int ballDirectionX = 1; -int ballDirectionY = 1; - -int ballSpeed = 10; // lower numbers are faster - -int ballX, ballY, oldBallX, oldBallY; - -void setup() { - // initialize the display - TFTscreen.begin(); - // black background - TFTscreen.background(0, 0, 0); -} - -void loop() { - - // save the width and height of the screen - int myWidth = TFTscreen.width(); - int myHeight = TFTscreen.height(); - - // map the paddle's location to the position of the potentiometers - paddleX = map(analogRead(A0), 512, -512, 0, myWidth) - 20 / 2; - paddleY = map(analogRead(A1), 512, -512, 0, myHeight) - 5 / 2; - - // set the fill color to black and erase the previous - // position of the paddle if different from present - TFTscreen.fill(0, 0, 0); - - if (oldPaddleX != paddleX || oldPaddleY != paddleY) { - TFTscreen.rect(oldPaddleX, oldPaddleY, 20, 5); - } - - // draw the paddle on screen, save the current position - // as the previous. - TFTscreen.fill(255, 255, 255); - - TFTscreen.rect(paddleX, paddleY, 20, 5); - oldPaddleX = paddleX; - oldPaddleY = paddleY; - - // update the ball's position and draw it on screen - if (millis() % ballSpeed < 2) { - moveBall(); - } -} - -// this function determines the ball's position on screen -void moveBall() { - // if the ball goes offscreen, reverse the direction: - if (ballX > TFTscreen.width() || ballX < 0) { - ballDirectionX = -ballDirectionX; - } - - if (ballY > TFTscreen.height() || ballY < 0) { - ballDirectionY = -ballDirectionY; - } - - // check if the ball and the paddle occupy the same space on screen - if (inPaddle(ballX, ballY, paddleX, paddleY, 20, 5)) { - ballDirectionX = -ballDirectionX; - ballDirectionY = -ballDirectionY; - } - - // update the ball's position - ballX += ballDirectionX; - ballY += ballDirectionY; - - // erase the ball's previous position - TFTscreen.fill(0, 0, 0); - - if (oldBallX != ballX || oldBallY != ballY) { - TFTscreen.rect(oldBallX, oldBallY, 5, 5); - } - - - // draw the ball's current position - TFTscreen.fill(255, 255, 255); - TFTscreen.rect(ballX, ballY, 5, 5); - - oldBallX = ballX; - oldBallY = ballY; - -} - -// this function checks the position of the ball -// to see if it intersects with the paddle -boolean inPaddle(int x, int y, int rectX, int rectY, int rectWidth, int rectHeight) { - boolean result = false; - - if ((x >= rectX && x <= (rectX + rectWidth)) && - (y >= rectY && y <= (rectY + rectHeight))) { - result = true; - } - - return result; -} - - diff --git a/libraries/TFT/extras/Adafruit-README.txt b/libraries/TFT/extras/Adafruit-README.txt deleted file mode 100644 index 6f3b682d..00000000 --- a/libraries/TFT/extras/Adafruit-README.txt +++ /dev/null @@ -1,21 +0,0 @@ -This is a library for the Adafruit 1.8" SPI display. -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - -Check out the links above for our tutorials and wiring diagrams. -These displays use SPI to communicate, 4 or 5 pins are required -to interface (RST is optional). -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -MIT license, all text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ST7735. Check that the Adafruit_ST7735 folder contains Adafruit_ST7735.cpp and Adafruit_ST7735. - -Place the Adafruit_ST7735 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE - -Also requires the Adafruit_GFX library for Arduino. diff --git a/libraries/TFT/extras/Adafruit-license.txt b/libraries/TFT/extras/Adafruit-license.txt deleted file mode 100644 index 4bbfa394..00000000 --- a/libraries/TFT/extras/Adafruit-license.txt +++ /dev/null @@ -1,25 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libraries/TFT/extras/README.md b/libraries/TFT/extras/README.md deleted file mode 100644 index 6f41794f..00000000 --- a/libraries/TFT/extras/README.md +++ /dev/null @@ -1,18 +0,0 @@ -TFT Library -============ - -An Arduino library for the Arduino TFT LCD screen. - -This library enables an Arduino board to communicate with an Arduino TFT LCD screen. It simplifies the process for drawing shapes, lines, images, and text to the screen. -The Arduino TFT library extends the Adafruit GFX, and Adafruit ST7735 libraries that it is based on. The GFX library is responsible for the drawing routines, while the ST7735 library is specific to the screen on the Arduino GTFT. The Arduino specific additions were designed to work as similarly to the Processing API as possible. - -Onboard the screen is a SD card slot, which can be used through the SD library. - -The TFT library relies on the SPI library for communication with the screen and SD card, and needs to be included in all sketches. - -https://github.com/adafruit/Adafruit-GFX-Library -https://github.com/adafruit/Adafruit-ST7735-Library -http://www.arduino.cc/en/Reference/SD -http://www.arduino.cc/en/Reference/SPI - -http://www.arduino.cc/en/Reference/TFTLibrary \ No newline at end of file diff --git a/libraries/TFT/keywords.txt b/libraries/TFT/keywords.txt deleted file mode 100644 index c8d33e41..00000000 --- a/libraries/TFT/keywords.txt +++ /dev/null @@ -1,20 +0,0 @@ -####################################### -# Syntax Coloring Map For Arduino GLCD -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -TFT KEYWORD1 TFTLibrary - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - - -####################################### -# Constants (LITERAL1) -####################################### - -EsploraTFT LITERAL1 diff --git a/libraries/TFT/library.properties b/libraries/TFT/library.properties deleted file mode 100644 index 0a727d49..00000000 --- a/libraries/TFT/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=TFT -version=1.0.4 -author=Arduino, Adafruit -maintainer=Arduino -sentence=Allows drawing text, images, and shapes on the Arduino TFT graphical display. For all Arduino boards. -paragraph=This library is compatible with most of the TFT display based on the ST7735 chipset -category=Display -url=http://www.arduino.cc/en/Reference/TFTLibrary -architectures=arc32 diff --git a/libraries/TFT/src/TFT.cpp b/libraries/TFT/src/TFT.cpp deleted file mode 100644 index 1bdf7ed3..00000000 --- a/libraries/TFT/src/TFT.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (c) 2013, Enrico Gueli All -rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "TFT.h" - -#if ARDUINO_AVR_ESPLORA -TFT EsploraTFT(7, 0, 1); -#endif - -TFT::TFT(uint8_t CS, uint8_t RS, uint8_t RST) - : Adafruit_ST7735(CS, RS, RST) -{ - // as we already know the orientation (landscape, therefore rotated), - // set default width and height without need to call begin() first. - _width = ST7735_TFTHEIGHT; - _height = ST7735_TFTWIDTH; -} - -void TFT::begin() { -//initR(INITR_REDTAB); - initG(); - setRotation(1); -} diff --git a/libraries/TFT/src/TFT.h b/libraries/TFT/src/TFT.h deleted file mode 100644 index 16791d6b..00000000 --- a/libraries/TFT/src/TFT.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2013, Enrico Gueli All -rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _ARDUINO_TFT_H -#define _ARDUINO_TFT_H - -#include "Arduino.h" -#include "utility/Adafruit_GFX.h" -#include "utility/Adafruit_ST7735.h" - -/// The Arduino LCD is a ST7735-based device. -/// By default, it is mounted horizontally. -/// TFT class follows the convention of other -/// Arduino library classes by adding a begin() method -/// to be called in the setup() routine. -/// @author Enrico Gueli -class TFT : public Adafruit_ST7735 { -public: - TFT(uint8_t CS, uint8_t RS, uint8_t RST); - - void begin(); -}; - -/// Esplora boards have hard-wired connections with -/// the Arduino LCD if mounted on the onboard connector. -#if ARDUINO_AVR_ESPLORA // are we building for Esplora? -extern TFT EsploraTFT; -#endif - -#endif // _ARDUINO_TFT_H diff --git a/libraries/TFT/src/utility/Adafruit_GFX.cpp b/libraries/TFT/src/utility/Adafruit_GFX.cpp deleted file mode 100644 index 6478c47c..00000000 --- a/libraries/TFT/src/utility/Adafruit_GFX.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* -This is the core graphics library for all our displays, providing a common -set of graphics primitives (points, lines, circles, etc.). It needs to be -paired with a hardware-specific library for each display device we carry -(to handle the lower-level functions). - -Adafruit invests time and resources providing this open source code, please -support Adafruit & open-source hardware by purchasing products from Adafruit! - -Copyright (c) 2013 Adafruit Industries. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "Adafruit_GFX.h" -#include "glcdfont.c" -#ifdef __AVR__ - #include -#else - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) -#endif - -Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : - WIDTH(w), HEIGHT(h) -{ - _width = WIDTH; - _height = HEIGHT; - rotation = 0; - cursor_y = cursor_x = 0; - textsize = 1; - textcolor = textbgcolor = 0xFFFF; - wrap = true; -} - -// draw a circle outline -void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - drawPixel(x0, y0+r, color); - drawPixel(x0, y0-r, color); - drawPixel(x0+r, y0, color); - drawPixel(x0-r, y0, color); - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 - x, y0 + y, color); - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 - x, y0 - y, color); - drawPixel(x0 + y, y0 + x, color); - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 + y, y0 - x, color); - drawPixel(x0 - y, y0 - x, color); - } -} - -void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, - int16_t r, uint8_t cornername, uint16_t color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) { - drawPixel(x0 + x, y0 + y, color); - drawPixel(x0 + y, y0 + x, color); - } - if (cornername & 0x2) { - drawPixel(x0 + x, y0 - y, color); - drawPixel(x0 + y, y0 - x, color); - } - if (cornername & 0x8) { - drawPixel(x0 - y, y0 + x, color); - drawPixel(x0 - x, y0 + y, color); - } - if (cornername & 0x1) { - drawPixel(x0 - y, y0 - x, color); - drawPixel(x0 - x, y0 - y, color); - } - } -} - -void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, - uint16_t color) -{ - drawFastVLine(x0, y0-r, 2*r+1, color); - fillCircleHelper(x0, y0, r, 3, 0, color); -} - -// used to do circles and roundrects -void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, - uint8_t cornername, int16_t delta, uint16_t color) -{ - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - if (cornername & 0x1) { - drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); - } - if (cornername & 0x2) { - drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); - drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); - } - } -} - -// Bresenham's algorithm - thx wikpedia -void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, - int16_t x1, int16_t y1, - uint16_t color) -{ - int16_t steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { - swap(x0, y0); - swap(x1, y1); - } - - if (x0 > x1) { - swap(x0, x1); - swap(y0, y1); - } - - int16_t dx, dy; - dx = x1 - x0; - dy = abs(y1 - y0); - - int16_t err = dx / 2; - int16_t ystep; - - if (y0 < y1) { - ystep = 1; - } else { - ystep = -1; - } - - for (; x0<=x1; x0++) { - if (steep) { - drawPixel(y0, x0, color); - } else { - drawPixel(x0, y0, color); - } - err -= dy; - if (err < 0) { - y0 += ystep; - err += dx; - } - } -} - - -// Draw a rectangle -void Adafruit_GFX::drawRect(int16_t x, int16_t y, - int16_t w, int16_t h, - uint16_t color) -{ - drawFastHLine(x, y, w, color); - drawFastHLine(x, y+h-1, w, color); - drawFastVLine(x, y, h, color); - drawFastVLine(x+w-1, y, h, color); -} - -void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, - int16_t h, uint16_t color) -{ - // Update in subclasses if desired! - drawLine(x, y, x, y+h-1, color); -} - - -void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, - int16_t w, uint16_t color) -{ - // Update in subclasses if desired! - drawLine(x, y, x+w-1, y, color); -} - -void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) -{ - // Update in subclasses if desired! - for (int16_t i=x; i= y1 >= y0) - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - if (y1 > y2) { - swap(y2, y1); swap(x2, x1); - } - if (y0 > y1) { - swap(y0, y1); swap(x0, x1); - } - - if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing - a = b = x0; - if(x1 < a) a = x1; - else if(x1 > b) b = x1; - if(x2 < a) a = x2; - else if(x2 > b) b = x2; - drawFastHLine(a, y0, b-a+1, color); - return; - } - - int16_t - dx01 = x1 - x0, - dy01 = y1 - y0, - dx02 = x2 - x0, - dy02 = y2 - y0, - dx12 = x2 - x1, - dy12 = y2 - y1, - sa = 0, - sb = 0; - - // For upper part of triangle, find scanline crossings for segments - // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 - // is included here (and second loop will be skipped, avoiding a /0 - // error there), otherwise scanline y1 is skipped here and handled - // in the second loop...which also avoids a /0 error here if y0=y1 - // (flat-topped triangle). - if(y1 == y2) last = y1; // Include y1 scanline - else last = y1-1; // Skip it - - for(y=y0; y<=last; y++) { - a = x0 + sa / dy01; - b = x0 + sb / dy02; - sa += dx01; - sb += dx02; - /* longhand: - a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } - - // For lower part of triangle, find scanline crossings for segments - // 0-2 and 1-2. This loop is skipped if y1=y2. - sa = dx12 * (y - y1); - sb = dx02 * (y - y0); - for(; y<=y2; y++) { - a = x1 + sa / dy12; - b = x0 + sb / dy02; - sa += dx12; - sb += dx02; - /* longhand: - a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); - b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); - */ - if(a > b) swap(a,b); - drawFastHLine(a, y, b-a+1, color); - } -} - -void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color) -{ - int16_t i, j, byteWidth = (w + 7) / 8; - - for(j=0; j> (i & 7))) { - drawPixel(x+i, y+j, color); - } - } - } -} - - -#if ARDUINO >= 100 -size_t Adafruit_GFX::write(uint8_t c) { -#else -void Adafruit_GFX::write(uint8_t c) { -#endif - if (c == '\n') { - cursor_y += textsize*8; - cursor_x = 0; - } else if (c == '\r') { - // skip em - } else { - drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); - cursor_x += textsize*6; - if (wrap && (cursor_x > (_width - textsize*6))) { - cursor_y += textsize*8; - cursor_x = 0; - } - } -#if ARDUINO >= 100 - return 1; -#endif -} - -// draw a character -void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, - uint16_t color, uint16_t bg, uint8_t size) -{ - if((x >= _width) || // Clip right - (y >= _height) || // Clip bottom - ((x + 6 * size - 1) < 0) || // Clip left - ((y + 8 * size - 1) < 0)) // Clip top - return; - - for (int8_t i=0; i<6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(font+(c*5)+i); - for (int8_t j = 0; j<8; j++) { - if (line & 0x1) { - if (size == 1) // default size - drawPixel(x+i, y+j, color); - else { // big size - fillRect(x+(i*size), y+(j*size), size, size, color); - } - } else if (bg != color) { - if (size == 1) // default size - drawPixel(x+i, y+j, bg); - else { // big size - fillRect(x+i*size, y+j*size, size, size, bg); - } - } - line >>= 1; - } - } -} - -void Adafruit_GFX::setCursor(int16_t x, int16_t y) -{ - cursor_x = x; - cursor_y = y; -} - - -void Adafruit_GFX::setTextSize(uint8_t s) -{ - textsize = (s > 0) ? s : 1; -} - - -void Adafruit_GFX::setTextColor(uint16_t c) { - textcolor = c; - textbgcolor = c; - // for 'transparent' background, we'll set the bg - // to the same as fg instead of using a flag -} - - void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) -{ - textcolor = c; - textbgcolor = b; -} - -void Adafruit_GFX::setTextWrap(boolean w) -{ - wrap = w; -} - -uint8_t Adafruit_GFX::getRotation(void) -{ - return rotation; -} - -void Adafruit_GFX::setRotation(uint8_t x) -{ - rotation = (x & 3); - switch (x) { - case 0: - case 2: - _width = WIDTH; - _height = HEIGHT; - break; - case 1: - case 3: - _width = HEIGHT; - _height = WIDTH; - break; - } -} - - - -// return the size of the display (per current rotation) -int16_t Adafruit_GFX::width(void) -{ - return _width; -} - -int16_t Adafruit_GFX::height(void) -{ - return _height; -} - -void Adafruit_GFX::invertDisplay(boolean i) -{ - // Do nothing, must be subclassed if supported -} - - -uint16_t Adafruit_GFX::newColor(uint8_t r, uint8_t g, uint8_t b) -{ - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); -} - -void Adafruit_GFX::background(uint8_t red, uint8_t green, uint8_t blue) -{ - background(newColor(red, green, blue)); -} - -void Adafruit_GFX::background(color c) { - fillScreen(c); -} - -void Adafruit_GFX::stroke(uint8_t red, uint8_t green, uint8_t blue) -{ - stroke(newColor(red, green, blue)); -} - -void Adafruit_GFX::stroke(color c) -{ - useStroke = true; - strokeColor = c; - setTextColor(c); -} - -void Adafruit_GFX::noStroke() -{ - useStroke = false; -} - -void Adafruit_GFX::noFill() { - useFill = false; -} - -void Adafruit_GFX::fill(uint8_t red, uint8_t green, uint8_t blue) -{ - fill(newColor(red, green, blue)); -} - -void Adafruit_GFX::fill(color c) -{ - useFill = true; - fillColor = c; -} - - -void Adafruit_GFX::text(const char * text, int16_t x, int16_t y) -{ - if (!useStroke) - return; - - setTextWrap(false); - setTextColor(strokeColor); - setCursor(x, y); - print(text); -} - -void Adafruit_GFX::textWrap(const char * text, int16_t x, int16_t y) -{ - if (!useStroke) - return; - - setTextWrap(true); - setTextColor(strokeColor); - setCursor(x, y); - print(text); -} - - -void Adafruit_GFX::textSize(uint8_t size) -{ - setTextSize(size); -} - -void Adafruit_GFX::point(int16_t x, int16_t y) -{ - if (!useStroke) - return; - - drawPixel(x, y, strokeColor); -} - -void Adafruit_GFX::line(int16_t x1, int16_t y1, int16_t x2, int16_t y2) -{ - if (!useStroke) - return; - - if (x1 == x2) { - if (y1 < y2) - drawFastVLine(x1, y1, y2 - y1, strokeColor); - else - drawFastVLine(x1, y2, y1 - y2, strokeColor); - } - else if (y1 == y2) { - if (x1 < x2) - drawFastHLine(x1, y1, x2 - x1, strokeColor); - else - drawFastHLine(x2, y1, x1 - x2, strokeColor); - } - else { - drawLine(x1, y1, x2, y2, strokeColor); - } -} - -void Adafruit_GFX::rect(int16_t x, int16_t y, int16_t width, int16_t height) -{ - if (useFill) { - fillRect(x, y, width, height, fillColor); - } - if (useStroke) { - drawRect(x, y, width, height, strokeColor); - } -} - -void Adafruit_GFX::rect(int16_t x, int16_t y, int16_t width, int16_t height, int16_t radius) -{ - if (radius == 0) { - rect(x, y, width, height); - } - if (useFill) { - fillRoundRect(x, y, width, height, radius, fillColor); - } - if (useStroke) { - drawRoundRect(x, y, width, height, radius, strokeColor); - } -} - -void Adafruit_GFX::circle(int16_t x, int16_t y, int16_t r) -{ - if (r == 0) - return; - - if (useFill) { - fillCircle(x, y, r, fillColor); - } - if (useStroke) { - drawCircle(x, y, r, strokeColor); - } -} - -void Adafruit_GFX::triangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3) -{ - if (useFill) { - fillTriangle(x1, y1, x2, y2, x3, y3, fillColor); - } - if (useStroke) { - drawTriangle(x1, y1, x2, y2, x3, y3, strokeColor); - } -} - -#if defined(__SD_H__) // Arduino SD library - -#define BUFFPIXEL 20 - -void Adafruit_GFX::image(PImage & img, uint16_t x, uint16_t y) { - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0; - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - - // Crop area to be loaded - w = img._bmpWidth; - h = img._bmpHeight; - if((x+w-1) >= width()) w = width() - x; - if((y+h-1) >= height()) h = height() - y; - - /* - // Set TFT address window to clipped image bounds - setAddrWindow(x, y, x+w-1, y+h-1); - */ - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - img._bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - //pushColor(tft.Color565(r,g,b)); - drawPixel(x + col, y + row, newColor(r, g, b)); - - } // end pixel - } // end scanline - -} - -#endif diff --git a/libraries/TFT/src/utility/Adafruit_GFX.h b/libraries/TFT/src/utility/Adafruit_GFX.h deleted file mode 100644 index 626e3d7e..00000000 --- a/libraries/TFT/src/utility/Adafruit_GFX.h +++ /dev/null @@ -1,372 +0,0 @@ -/****************************************************************** - This is the core graphics library for all our displays, providing - basic graphics primitives (points, lines, circles, etc.). It needs - to be paired with a hardware-specific library for each display - device we carry (handling the lower-level functions). - - Adafruit invests time and resources providing this open - source code, please support Adafruit and open-source hardware - by purchasing products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - Processing-like API written by Enrico Gueli for Officine Arduino. - BSD license, check license.txt for more information. - All text above must be included in any redistribution. - ******************************************************************/ - -#ifndef _ADAFRUIT_GFX_H -#define _ADAFRUIT_GFX_H - -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif - -/* - * This library can work with or without the presence of an SD - * reading library (to load images). At the moment, only the - * Arduino SD library is supported; it is included in - * standard Arduino libraries. - * - * The presence of the SD library is detected by looking at the - * __SD_H__ preprocessor variable, defined into - * Arduino SD library to avoid double inclusion. This means - * that in order to use the image-related API of Adafruit_GFX, - * SD.h *must* be included before Adafruit_GFX. - * - * The bottom part of this include file contains the actual image - * loading code; if it was in a separate .cpp file, there were no - * way to check if the SD library was present or not. - * - * A partial solution was to include SD.h anyway, see if that works - * (i.e. it is found in the include search path) and act accordingly. - * But this solution relied on the preprocessor to issue only a - * warning when an include file is not found. Avr-gcc, used for - * Arduino 8-bit MCUs, does that, but the standard gcc-4.4, used for - * Arduino Due, issues a fatal error and stops compilation. - * - * The best solution so far is to put the code here. It works if this - * include is used only in one .cpp file in the build (this is the - * case of most Arduino sketches); if used in multiple .cpp files, - * the linker may complain about duplicate definitions. - * - */ - -#if defined(__SD_H__) // Arduino SD library - #include "PImage.h" -#else - #warning "The SD library was not found. loadImage() and image() won't be supported." -#endif - -#define swap(a, b) { int16_t t = a; a = b; b = t; } - -/* TODO -enum RectMode { - CORNER, - CORNERS, - RADIUS, - CENTER -}; -*/ - -typedef uint16_t color; - -class Adafruit_GFX : public Print { - public: - - Adafruit_GFX(int16_t w, int16_t h); // Constructor - - // This MUST be defined by the subclass - virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; - - - - // These MAY be overridden by the subclass to provide device-specific - // optimized code. Otherwise 'generic' versions are used. - virtual void - drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - drawRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color), - fillScreen(uint16_t color), - invertDisplay(boolean i); - -// These exist only with Adafruit_GFX (no subclass overrides) - void - drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - drawCircleHelper(int16_t x0, int16_t y0, - int16_t r, uint8_t cornername, uint16_t color), - fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), - fillCircleHelper(int16_t x0, int16_t y0, int16_t r, - uint8_t cornername, int16_t delta, uint16_t color), - - drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, - int16_t x2, int16_t y2, uint16_t color), - drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, - int16_t radius, uint16_t color), - - drawBitmap(int16_t x, int16_t y, - const uint8_t *bitmap, int16_t w, int16_t h, - uint16_t color), - drawChar(int16_t x, int16_t y, unsigned char c, - uint16_t color, uint16_t bg, uint8_t size), - setCursor(int16_t x, int16_t y), - setTextColor(uint16_t c), - setTextColor(uint16_t c, uint16_t bg), - setTextSize(uint8_t s), - setTextWrap(boolean w), - setRotation(uint8_t r); - -#if ARDUINO >= 100 - virtual size_t write(uint8_t); -#else - virtual void write(uint8_t); -#endif - - int16_t - height(void), - width(void); - - - uint8_t getRotation(void); - - - /* - * Processing-like graphics primitives - */ - - /// transforms a color in 16-bit form given the RGB components. - /// The default implementation makes a 5-bit red, a 6-bit - /// green and a 5-bit blue (MSB to LSB). Devices that use - /// different scheme should override this. - virtual uint16_t newColor(uint8_t red, uint8_t green, uint8_t blue); - - - void - // http://processing.org/reference/background_.html - background(uint8_t red, uint8_t green, uint8_t blue), - background(color c), - - // http://processing.org/reference/fill_.html - fill(uint8_t red, uint8_t green, uint8_t blue), - fill(color c), - - // http://processing.org/reference/noFill_.html - noFill(), - - // http://processing.org/reference/stroke_.html - stroke(uint8_t red, uint8_t green, uint8_t blue), - stroke(color c), - - // http://processing.org/reference/noStroke_.html - noStroke(), - - text(const char * text, int16_t x, int16_t y), - textWrap(const char * text, int16_t x, int16_t y), - - textSize(uint8_t size), - - // similar to ellipse() in Processing, but with - // a single radius. - // http://processing.org/reference/ellipse_.html - circle(int16_t x, int16_t y, int16_t r), - point(int16_t x, int16_t y), - line(int16_t x1, int16_t y1, int16_t x2, int16_t y2), - quad(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3, int16_t x4, int16_t y4), -rect(int16_t x, int16_t y, int16_t width, int16_t height), - rect(int16_t x, int16_t y, int16_t width, int16_t height, int16_t radius), - triangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3); - - /* TODO - void rectMode(RectMode mode); - - void pushStyle(); - void popStyle(); - */ - -#if defined(__SD_H__) // Arduino SD library - PImage loadImage(const char * fileName) { return PImage::loadImage(fileName); } - - void image(PImage & img, uint16_t x, uint16_t y); -#endif - - protected: - int16_t - WIDTH, HEIGHT; // this is the 'raw' display w/h - never changes - int16_t - _width, _height, // dependent on rotation - cursor_x, cursor_y; - uint16_t - textcolor, textbgcolor; - uint8_t - textsize, - rotation; - boolean - wrap; // If set, 'wrap' text at right edge of display - - /* - * Processing-style graphics state - */ - - color strokeColor; - bool useStroke; - color fillColor; - bool useFill; -}; - -#if defined(__SD_H__) // Arduino SD library - -#define BUFFPIXEL 20 - -void Adafruit_GFX::image(PImage & img, uint16_t x, uint16_t y) { - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0; - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - - // Crop area to be loaded - w = img._bmpWidth; - h = img._bmpHeight; - if((x+w-1) >= width()) w = width() - x; - if((y+h-1) >= height()) h = height() - y; - - /* - // Set TFT address window to clipped image bounds - setAddrWindow(x, y, x+w-1, y+h-1); - */ - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - img._bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - //pushColor(tft.Color565(r,g,b)); - drawPixel(x + col, y + row, newColor(r, g, b)); - - } // end pixel - } // end scanline - -} - - - - -// These read 16- and 32-bit types from the SD card file. -// BMP data is stored little-endian, Arduino is little-endian too. -// May need to reverse subscript order if porting elsewhere. - -uint16_t PImage::read16(File f) { - uint16_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); // MSB - return result; -} - -uint32_t PImage::read32(File f) { - uint32_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); - ((uint8_t *)&result)[2] = f.read(); - ((uint8_t *)&result)[3] = f.read(); // MSB - return result; -} - - -PImage PImage::loadImage(const char * fileName) { - File bmpFile; - int bmpWidth, bmpHeight; // W+H in pixels - uint8_t bmpDepth; // Bit depth (currently must be 24) - uint32_t bmpImageoffset; // Start of image data in file - uint32_t rowSize; // Not always = bmpWidth; may have padding - bool flip = true; // BMP is stored bottom-to-top - - - // Open requested file on SD card - if ((bmpFile = SD.open(fileName)) == NULL) { - Serial.print(F("loadImage: file not found: ")); - Serial.println(fileName); - return PImage(); // load error - } - - - - // Parse BMP header - if(read16(bmpFile) != 0x4D42) { // BMP signature - Serial.println(F("loadImage: file doesn't look like a BMP")); - return PImage(); - } - - Serial.print(F("File size: ")); Serial.println(read32(bmpFile)); - (void)read32(bmpFile); // Read & ignore creator bytes - bmpImageoffset = read32(bmpFile); // Start of image data - Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); - // Read DIB header - Serial.print(F("Header size: ")); Serial.println(read32(bmpFile)); - bmpWidth = read32(bmpFile); - bmpHeight = read32(bmpFile); - if(read16(bmpFile) != 1) { // # planes -- must be '1' - Serial.println(F("loadImage: invalid n. of planes")); - return PImage(); - } - - bmpDepth = read16(bmpFile); // bits per pixel - Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); - if((bmpDepth != 24) || (read32(bmpFile) != 0)) { // 0 = uncompressed { - Serial.println(F("loadImage: invalid pixel format")); - return PImage(); - } - - Serial.print(F("Image size: ")); - Serial.print(bmpWidth); - Serial.print('x'); - Serial.println(bmpHeight); - - // BMP rows are padded (if needed) to 4-byte boundary - rowSize = (bmpWidth * 3 + 3) & ~3; - - // If bmpHeight is negative, image is in top-down order. - // This is not canon but has been observed in the wild. - if(bmpHeight < 0) { - bmpHeight = -bmpHeight; - flip = false; - } - - return PImage(bmpFile, bmpWidth, bmpHeight, bmpDepth, bmpImageoffset, rowSize, flip); -} - -#endif - -#endif // _ADAFRUIT_GFX_H diff --git a/libraries/TFT/src/utility/Adafruit_ST7735.cpp b/libraries/TFT/src/utility/Adafruit_ST7735.cpp deleted file mode 100644 index c9698a6e..00000000 --- a/libraries/TFT/src/utility/Adafruit_ST7735.cpp +++ /dev/null @@ -1,751 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 - as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include "Adafruit_ST7735.h" -#include -#include -#include "pins_arduino.h" -#include "wiring_private.h" -#include - -inline uint16_t swapcolor(uint16_t x) { - return (x << 11) | (x & 0x07E0) | (x >> 11); -} - - -// Constructor when using software SPI. All output pins are configurable. -Adafruit_ST7735::Adafruit_ST7735(uint8_t cs, uint8_t rs, uint8_t sid, - uint8_t sclk, uint8_t rst) : Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT) -{ - _cs = cs; - _rs = rs; - _sid = sid; - _sclk = sclk; - _rst = rst; - hwSPI = false; -} - - -// Constructor when using hardware SPI. Faster, but must use SPI pins -// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.) -Adafruit_ST7735::Adafruit_ST7735(uint8_t cs, uint8_t rs, uint8_t rst) : -Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT) -{ - _cs = cs; - _rs = rs; - _rst = rst; - hwSPI = true; - _sid = _sclk = 0; -} - - -inline void Adafruit_ST7735::spiwrite(uint8_t c) { - - //Serial.println(c, HEX); - - if (hwSPI) { - SPI.transfer(c); - } else { - // Fast SPI bitbang swiped from LPD8806 library - for(uint8_t bit = 0x80; bit; bit >>= 1) { - if(c & bit) *dataport |= datapinmask; - else *dataport &= ~datapinmask; - *clkport |= clkpinmask; - *clkport &= ~clkpinmask; - } - } -} - - -void Adafruit_ST7735::writecommand(uint8_t c) { -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, LOW); -#else - *rsport &= ~rspinmask; -#endif - *csport &= ~cspinmask; - - //Serial.print("C "); - spiwrite(c); - - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::writedata(uint8_t c) { -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - - //Serial.print("D "); - spiwrite(c); - - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - -// Rather than a bazillion writecommand() and writedata() calls, screen -// initialization commands and arguments are organized in these tables -// stored in PROGMEM. The table may look bulky, but that's mostly the -// formatting -- storage-wise this is hundreds of bytes more compact -// than the equivalent code. Companion function follows. -#define DELAY 0x80 -PROGMEM const static unsigned char - Bcmd[] = { // Initialization commands for 7735B screens - 18, // 18 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 50, // 50 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay: - 0x05, // 16-bit color - 10, // 10 ms delay - ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay: - 0x00, // fastest refresh - 0x06, // 6 lines front porch - 0x03, // 3 lines back porch - 10, // 10 ms delay - ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg: - 0x08, // Row addr/col addr, bottom to top refresh - ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay: - 0x15, // 1 clk cycle nonoverlap, 2 cycle gate - // rise, 3 cycle osc equalize - 0x02, // Fix on VTL - ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg: - 0x0, // Line inversion - ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay: - 0x02, // GVDD = 4.7V - 0x70, // 1.0uA - 10, // 10 ms delay - ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay: - 0x05, // VGH = 14.7V, VGL = -7.35V - ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay: - 0x01, // Opamp current small - 0x02, // Boost frequency - ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay: - 0x3C, // VCOMH = 4V - 0x38, // VCOML = -1.1V - 10, // 10 ms delay - ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay: - 0x11, 0x15, - ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay: - 0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what - 0x21, 0x1B, 0x13, 0x19, // these config values represent) - 0x17, 0x15, 0x1E, 0x2B, - 0x04, 0x05, 0x02, 0x0E, - ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay: - 0x0B, 0x14, 0x08, 0x1E, // (ditto) - 0x22, 0x1D, 0x18, 0x1E, - 0x1B, 0x1A, 0x24, 0x2B, - 0x06, 0x06, 0x02, 0x0F, - 10, // 10 ms delay - ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 2 - 0x00, 0x81, // XEND = 129 - ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 1 - 0x00, 0x81, // XEND = 160 - ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay - 255 }, // 255 = 500 ms delay - - Rcmd1[] = { // Init for 7735R, part 1 (red or green tab) - 15, // 15 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay - 150, // 150 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay - 255, // 500 ms delay - ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args: - 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) - ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args: - 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) - ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args: - 0x01, 0x2C, 0x2D, // Dot inversion mode - 0x01, 0x2C, 0x2D, // Line inversion mode - ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay: - 0x07, // No inversion - ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay: - 0xA2, - 0x02, // -4.6V - 0x84, // AUTO mode - ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay: - 0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD - ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay: - 0x0A, // Opamp current small - 0x00, // Boost frequency - ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay: - 0x8A, // BCLK/2, Opamp current small & Medium low - 0x2A, - ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay: - 0x8A, 0xEE, - ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay: - 0x0E, - ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay - ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg: - 0xC8, // row addr/col addr, bottom to top refresh - ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay: - 0x05 }, // 16-bit color - - Rcmd2green[] = { // Init for 7735R, part 2 (green tab only) - 2, // 2 commands in list: - ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 0 - 0x00, 0x7F+0x02, // XEND = 127 - ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay: - 0x00, 0x01, // XSTART = 0 - 0x00, 0x9F+0x01 }, // XEND = 159 - Rcmd2red[] = { // Init for 7735R, part 2 (red tab only) - 2, // 2 commands in list: - ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x7F, // XEND = 127 - ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x9F }, // XEND = 159 - - Rcmd3[] = { // Init for 7735R, part 3 (red or green tab) - 4, // 4 commands in list: - ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay: - 0x02, 0x1c, 0x07, 0x12, - 0x37, 0x32, 0x29, 0x2d, - 0x29, 0x25, 0x2B, 0x39, - 0x00, 0x01, 0x03, 0x10, - ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay: - 0x03, 0x1d, 0x07, 0x06, - 0x2E, 0x2C, 0x29, 0x2D, - 0x2E, 0x2E, 0x37, 0x3F, - 0x00, 0x00, 0x02, 0x10, - ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay - 100 }, // 100 ms delay - Gcmd[] = { // Initialization commands for 7735B screens - 19, // 18 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 50, // 50 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 100, // 255 = 500 ms delay - 0x26 , 1, // 3: Set default gamma - 0x04, // 16-bit color - 0xb1, 2, // 4: Frame Rate - 0x0b, - 0x14, - 0xc0, 2, // 5: VRH1[4:0] & VC[2:0] - 0x08, - 0x00, - 0xc1, 1, // 6: BT[2:0] - 0x05, - 0xc5, 2, // 7: VMH[6:0] & VML[6:0] - 0x41, - 0x30, - 0xc7, 1, // 8: LCD Driving control - 0xc1, - 0xEC, 1, // 9: Set pumping color freq - 0x1b, - 0x3a , 1 + DELAY, // 10: Set color format - 0x55, // 16-bit color - 100, - 0x2a, 4, // 11: Set Column Address - 0x00, - 0x00, - 0x00, - 0x7f, - 0x2b, 4, // 12: Set Page Address - 0x00, - 0x00, - 0x00, - 0x9f, - 0x36, 1, // 12+1: Set Scanning Direction - 0xc8, - 0xb7, 1, // 14: Set Source Output Direciton - 0x00, - 0xf2, 1, // 15: Enable Gamma bit - 0x00, - 0xe0, 15 + DELAY, // 16: magic - 0x28, 0x24, 0x22, 0x31, - 0x2b, 0x0e, 0x53, 0xa5, - 0x42, 0x16, 0x18, 0x12, - 0x1a, 0x14, 0x03, - 50, - 0xe1, 15 + DELAY, // 17: more magic - 0x17, 0x1b, 0x1d, 0x0e, - 0x14, 0x11, 0x2c, 0xa5, - 0x3d, 0x09, 0x27, 0x2d, - 0x25, 0x2b, 0x3c, - 50, - ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay - 255 }; // 255 = 500 ms delay - - - -// Companion code to the above tables. Reads and issues -// a series of LCD commands stored in PROGMEM byte array. -void Adafruit_ST7735::commandList(const uint8_t *addr) { - - uint8_t numCommands, numArgs; - uint16_t ms; - - numCommands = pgm_read_byte(addr++); // Number of commands to follow - while(numCommands--) { // For each command... - writecommand(pgm_read_byte(addr++)); // Read, issue command - numArgs = pgm_read_byte(addr++); // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs--) { // For each argument... - writedata(pgm_read_byte(addr++)); // Read, issue argument - } - - if(ms) { - ms = pgm_read_byte(addr++); // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - delay(ms); - } - } -} - - -// Initialization code common to both 'B' and 'R' type displays -void Adafruit_ST7735::commonInit(const uint8_t *cmdList) { - - colstart = rowstart = 0; // May be overridden in init func - - pinMode(_rs, OUTPUT); - pinMode(_cs, OUTPUT); - csport = portOutputRegister(digitalPinToPort(_cs)); - cspinmask = digitalPinToBitMask(_cs); - rsport = portOutputRegister(digitalPinToPort(_rs)); - rspinmask = digitalPinToBitMask(_rs); - - if(hwSPI) { // Using hardware SPI - SPI.begin(); -#ifdef SPI_HAS_TRANSACTION - spisettings = SPISettings(4000000L, MSBFIRST, SPI_MODE0); -#else -#if defined(ARDUINO_ARCH_SAM) - SPI.setClockDivider(24); // 4 MHz (half speed) -#else - SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed) -#endif - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); -#endif // SPI_HAS_TRANSACTION - } else { - pinMode(_sclk, OUTPUT); - pinMode(_sid , OUTPUT); - clkport = portOutputRegister(digitalPinToPort(_sclk)); - clkpinmask = digitalPinToBitMask(_sclk); - dataport = portOutputRegister(digitalPinToPort(_sid)); - datapinmask = digitalPinToBitMask(_sid); - *clkport &= ~clkpinmask; - *dataport &= ~datapinmask; - } - - // toggle RST low to reset; CS low so it'll listen to us - *csport &= ~cspinmask; - if (_rst) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(500); - digitalWrite(_rst, LOW); - delay(500); - digitalWrite(_rst, HIGH); - delay(500); - } - - if(cmdList) commandList(cmdList); -} - - -// Initialization for ST7735B screens -void Adafruit_ST7735::initB(void) { - commonInit(Bcmd); -} - - -// Initialization for ST7735B screens -void Adafruit_ST7735::initG(void) { - commonInit(Gcmd); -} - - -// Initialization for ST7735R screens (green or red tabs) -void Adafruit_ST7735::initR(uint8_t options) { - commonInit(Rcmd1); - if(options == INITR_GREENTAB) { - commandList(Rcmd2green); - colstart = 2; - rowstart = 1; - } else { - // colstart, rowstart left at default '0' values - commandList(Rcmd2red); - } - commandList(Rcmd3); - tabcolor = options; -} - - -void Adafruit_ST7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, - uint8_t y1) { - - writecommand(ST7735_CASET); // Column addr set - writedata(0x00); - writedata(x0+colstart); // XSTART - writedata(0x00); - writedata(x1+colstart); // XEND - - writecommand(ST7735_RASET); // Row addr set - writedata(0x00); - writedata(y0+rowstart); // YSTART - writedata(0x00); - writedata(y1+rowstart); // YEND - - writecommand(ST7735_RAMWR); // write to RAM -} - - -void Adafruit_ST7735::pushColor(uint16_t color) { -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - - if (tabcolor == INITR_BLACKTAB) color = swapcolor(color); - spiwrite(color >> 8); - spiwrite(color); - - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - -void Adafruit_ST7735::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - - setAddrWindow(x,y,x+1,y+1); - -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - - if (tabcolor == INITR_BLACKTAB) color = swapcolor(color); - - spiwrite(color >> 8); - spiwrite(color); - - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((y+h-1) >= _height) h = _height-y; - setAddrWindow(x, y, x, y+h-1); - - if (tabcolor == INITR_BLACKTAB) color = swapcolor(color); - - uint8_t hi = color >> 8, lo = color; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - while (h--) { - spiwrite(hi); - spiwrite(lo); - } - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - setAddrWindow(x, y, x+w-1, y); - - if (tabcolor == INITR_BLACKTAB) color = swapcolor(color); - - uint8_t hi = color >> 8, lo = color; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - while (w--) { - spiwrite(hi); - spiwrite(lo); - } - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - - -void Adafruit_ST7735::fillScreen(uint16_t color) { - fillRect(0, 0, _width, _height, color); -} - - - -// fill a rectangle -void Adafruit_ST7735::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - if (tabcolor == INITR_BLACKTAB) color = swapcolor(color); - - setAddrWindow(x, y, x+w-1, y+h-1); - - uint8_t hi = color >> 8, lo = color; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.beginTransaction(spisettings); -#endif - -#ifdef __ARDUINO_ARC__ - digitalWrite(_rs, HIGH); -#else - *rsport |= rspinmask; -#endif - *csport &= ~cspinmask; - for(y=h; y>0; y--) { - for(x=w; x>0; x--) { - spiwrite(hi); - spiwrite(lo); - } - } - - *csport |= cspinmask; -#ifdef SPI_HAS_TRANSACTION - if (hwSPI) SPI.endTransaction(); -#endif -} - - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_RGB 0x08 -#define MADCTL_MH 0x04 - -void Adafruit_ST7735::setRotation(uint8_t m) { - - writecommand(ST7735_MADCTL); - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - writedata(MADCTL_MX | MADCTL_MY | MADCTL_RGB); - _width = ST7735_TFTWIDTH; - _height = ST7735_TFTHEIGHT; - break; - case 1: - writedata(MADCTL_MY | MADCTL_MV | MADCTL_RGB); - _width = ST7735_TFTHEIGHT; - _height = ST7735_TFTWIDTH; - break; - case 2: - writedata(MADCTL_RGB); - _width = ST7735_TFTWIDTH; - _height = ST7735_TFTHEIGHT; - break; - case 3: - writedata(MADCTL_MX | MADCTL_MV | MADCTL_RGB); - _width = ST7735_TFTHEIGHT; - _height = ST7735_TFTWIDTH; - break; - } -} - - -void Adafruit_ST7735::invertDisplay(boolean i) { - writecommand(i ? ST7735_INVON : ST7735_INVOFF); -} - - -////////// stuff not actively being used, but kept for posterity -/* - - uint8_t Adafruit_ST7735::spiread(void) { - uint8_t r = 0; - if (_sid > 0) { - r = shiftIn(_sid, _sclk, MSBFIRST); - } else { - //SID_DDR &= ~_BV(SID); - //int8_t i; - //for (i=7; i>=0; i--) { - // SCLK_PORT &= ~_BV(SCLK); - // r <<= 1; - // r |= (SID_PIN >> SID) & 0x1; - // SCLK_PORT |= _BV(SCLK); - //} - //SID_DDR |= _BV(SID); - - } - return r; - } - - - void Adafruit_ST7735::dummyclock(void) { - - if (_sid > 0) { - digitalWrite(_sclk, LOW); - digitalWrite(_sclk, HIGH); - } else { - // SCLK_PORT &= ~_BV(SCLK); - //SCLK_PORT |= _BV(SCLK); - } - } - uint8_t Adafruit_ST7735::readdata(void) { - *portOutputRegister(rsport) |= rspin; - - *portOutputRegister(csport) &= ~ cspin; - - uint8_t r = spiread(); - - *portOutputRegister(csport) |= cspin; - - return r; - - } - - uint8_t Adafruit_ST7735::readcommand8(uint8_t c) { - digitalWrite(_rs, LOW); - - *portOutputRegister(csport) &= ~ cspin; - - spiwrite(c); - - digitalWrite(_rs, HIGH); - pinMode(_sid, INPUT); // input! - digitalWrite(_sid, LOW); // low - spiread(); - uint8_t r = spiread(); - - - *portOutputRegister(csport) |= cspin; - - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - - uint16_t Adafruit_ST7735::readcommand16(uint8_t c) { - digitalWrite(_rs, LOW); - if (_cs) - digitalWrite(_cs, LOW); - - spiwrite(c); - pinMode(_sid, INPUT); // input! - uint16_t r = spiread(); - r <<= 8; - r |= spiread(); - if (_cs) - digitalWrite(_cs, HIGH); - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - uint32_t Adafruit_ST7735::readcommand32(uint8_t c) { - digitalWrite(_rs, LOW); - if (_cs) - digitalWrite(_cs, LOW); - spiwrite(c); - pinMode(_sid, INPUT); // input! - - dummyclock(); - dummyclock(); - - uint32_t r = spiread(); - r <<= 8; - r |= spiread(); - r <<= 8; - r |= spiread(); - r <<= 8; - r |= spiread(); - if (_cs) - digitalWrite(_cs, HIGH); - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - */ diff --git a/libraries/TFT/src/utility/Adafruit_ST7735.h b/libraries/TFT/src/utility/Adafruit_ST7735.h deleted file mode 100644 index 077045dc..00000000 --- a/libraries/TFT/src/utility/Adafruit_ST7735.h +++ /dev/null @@ -1,155 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 - as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#ifndef _ADAFRUIT_ST7735H_ -#define _ADAFRUIT_ST7735H_ - -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif -#include "Adafruit_GFX.h" -#include -#include - -// some flags for initR() :( -#define INITR_GREENTAB 0x0 -#define INITR_REDTAB 0x1 -#define INITR_BLACKTAB 0x2 - -#define ST7735_TFTWIDTH 128 -#define ST7735_TFTHEIGHT 160 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -// Color definitions -#define ST7735_BLACK 0x0000 -#define ST7735_BLUE 0x001F -#define ST7735_RED 0xF800 -#define ST7735_GREEN 0x07E0 -#define ST7735_CYAN 0x07FF -#define ST7735_MAGENTA 0xF81F -#define ST7735_YELLOW 0xFFE0 -#define ST7735_WHITE 0xFFFF - - -class Adafruit_ST7735 : public Adafruit_GFX { - - public: - - Adafruit_ST7735(uint8_t CS, uint8_t RS, uint8_t SID, uint8_t SCLK, - uint8_t RST); - Adafruit_ST7735(uint8_t CS, uint8_t RS, uint8_t RST); - - void initB(void), // for ST7735B displays - initG(void), // for ILI9163C displays - initR(uint8_t options = INITR_GREENTAB), // for ST7735R - setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1), - pushColor(uint16_t color), - fillScreen(uint16_t color), - drawPixel(int16_t x, int16_t y, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color), - setRotation(uint8_t r), - invertDisplay(boolean i); - uint16_t Color565(uint8_t r, uint8_t g, uint8_t b) { return newColor(r, g, b);} - - /* These are not for current use, 8-bit protocol only! - uint8_t readdata(void), - readcommand8(uint8_t); - uint16_t readcommand16(uint8_t); - uint32_t readcommand32(uint8_t); - void dummyclock(void); - */ - - private: - uint8_t tabcolor; - - void spiwrite(uint8_t), - writecommand(uint8_t c), - writedata(uint8_t d), - commandList(const uint8_t *addr), - commonInit(const uint8_t *cmdList); -//uint8_t spiread(void); - - boolean hwSPI; -#ifdef SPI_HAS_TRANSACTION - SPISettings spisettings; -#endif -#if defined(ARDUINO_ARCH_SAM) || defined(__ARDUINO_ARC__) - volatile uint32_t *dataport, *clkport, *csport, *rsport; - uint32_t _cs, _rs, _rst, _sid, _sclk, - datapinmask, clkpinmask, cspinmask, rspinmask, - colstart, rowstart; // some displays need this changed - #else - volatile uint8_t *dataport, *clkport, *csport, *rsport; - uint8_t _cs, _rs, _rst, _sid, _sclk, - datapinmask, clkpinmask, cspinmask, rspinmask, - colstart, rowstart; // some displays need this changed - #endif -}; - -#endif diff --git a/libraries/TFT/src/utility/PImage.h b/libraries/TFT/src/utility/PImage.h deleted file mode 100644 index ed99db0b..00000000 --- a/libraries/TFT/src/utility/PImage.h +++ /dev/null @@ -1,65 +0,0 @@ - - -#ifndef _PIMAGE_H -#define _PIMAGE_H - -class Adafruit_GFX; - -#if defined(__SD_H__) // Arduino SD library - - -/// This class mimics Processing's PImage, but with fewer -/// capabilities. It allows an image stored in the SD card to be -/// drawn to the display. -/// @author Enrico Gueli -class PImage { -public: - PImage() : - _valid(false), - _bmpWidth(0), - _bmpHeight(0) { } - - void draw(Adafruit_GFX & glcd, int16_t x, int16_t y); - - static PImage loadImage(const char * fileName); - - void close() { _bmpFile.close(); } - - bool isValid() { return _valid; } - - int width() { return _bmpWidth; } - int height() { return _bmpHeight; } - -private: - friend class Adafruit_GFX; - - File _bmpFile; - int _bmpWidth, _bmpHeight; // W+H in pixels - uint8_t _bmpDepth; // Bit depth (currently must be 24) - uint32_t _bmpImageoffset; // Start of image data in file - uint32_t _rowSize; // Not always = bmpWidth; may have padding - bool _flip; - - bool _valid; - - PImage(File & bmpFile, int bmpWidth, int bmpHeight, uint8_t bmpDepth, uint32_t bmpImageoffset, uint32_t rowSize, bool flip) : - _bmpFile(bmpFile), - _bmpWidth(bmpWidth), - _bmpHeight(bmpHeight), - _bmpDepth(bmpDepth), - _bmpImageoffset(bmpImageoffset), - _rowSize(rowSize), - _flip(flip), - _valid(true) // since Adafruit_GFX is friend, we could just let it write the variables and save some CPU cycles - { } - - static uint16_t read16(File f); - static uint32_t read32(File f); - - // TODO close the file in ~PImage and PImage(const PImage&) - -}; - -#endif - -#endif // _PIMAGE_H diff --git a/libraries/TFT/src/utility/glcdfont.c b/libraries/TFT/src/utility/glcdfont.c deleted file mode 100644 index 2f857b06..00000000 --- a/libraries/TFT/src/utility/glcdfont.c +++ /dev/null @@ -1,268 +0,0 @@ -#if !defined(ARDUINO_ARCH_SAM) && !defined(__ARDUINO_ARC__) -#include -#endif -#include - -#ifndef FONT5X7_H -#define FONT5X7_H - -// standard ascii 5x7 font - -static const unsigned char font[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, - 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, - 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, - 0x18, 0x3C, 0x7E, 0x3C, 0x18, - 0x1C, 0x57, 0x7D, 0x57, 0x1C, - 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, - 0x00, 0x18, 0x3C, 0x18, 0x00, - 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, - 0x00, 0x18, 0x24, 0x18, 0x00, - 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, - 0x30, 0x48, 0x3A, 0x06, 0x0E, - 0x26, 0x29, 0x79, 0x29, 0x26, - 0x40, 0x7F, 0x05, 0x05, 0x07, - 0x40, 0x7F, 0x05, 0x25, 0x3F, - 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, - 0x7F, 0x3E, 0x1C, 0x1C, 0x08, - 0x08, 0x1C, 0x1C, 0x3E, 0x7F, - 0x14, 0x22, 0x7F, 0x22, 0x14, - 0x5F, 0x5F, 0x00, 0x5F, 0x5F, - 0x06, 0x09, 0x7F, 0x01, 0x7F, - 0x00, 0x66, 0x89, 0x95, 0x6A, - 0x60, 0x60, 0x60, 0x60, 0x60, - 0x94, 0xA2, 0xFF, 0xA2, 0x94, - 0x08, 0x04, 0x7E, 0x04, 0x08, - 0x10, 0x20, 0x7E, 0x20, 0x10, - 0x08, 0x08, 0x2A, 0x1C, 0x08, - 0x08, 0x1C, 0x2A, 0x08, 0x08, - 0x1E, 0x10, 0x10, 0x10, 0x10, - 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, - 0x30, 0x38, 0x3E, 0x38, 0x30, - 0x06, 0x0E, 0x3E, 0x0E, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5F, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x07, 0x00, - 0x14, 0x7F, 0x14, 0x7F, 0x14, - 0x24, 0x2A, 0x7F, 0x2A, 0x12, - 0x23, 0x13, 0x08, 0x64, 0x62, - 0x36, 0x49, 0x56, 0x20, 0x50, - 0x00, 0x08, 0x07, 0x03, 0x00, - 0x00, 0x1C, 0x22, 0x41, 0x00, - 0x00, 0x41, 0x22, 0x1C, 0x00, - 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, - 0x08, 0x08, 0x3E, 0x08, 0x08, - 0x00, 0x80, 0x70, 0x30, 0x00, - 0x08, 0x08, 0x08, 0x08, 0x08, - 0x00, 0x00, 0x60, 0x60, 0x00, - 0x20, 0x10, 0x08, 0x04, 0x02, - 0x3E, 0x51, 0x49, 0x45, 0x3E, - 0x00, 0x42, 0x7F, 0x40, 0x00, - 0x72, 0x49, 0x49, 0x49, 0x46, - 0x21, 0x41, 0x49, 0x4D, 0x33, - 0x18, 0x14, 0x12, 0x7F, 0x10, - 0x27, 0x45, 0x45, 0x45, 0x39, - 0x3C, 0x4A, 0x49, 0x49, 0x31, - 0x41, 0x21, 0x11, 0x09, 0x07, - 0x36, 0x49, 0x49, 0x49, 0x36, - 0x46, 0x49, 0x49, 0x29, 0x1E, - 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x40, 0x34, 0x00, 0x00, - 0x00, 0x08, 0x14, 0x22, 0x41, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x00, 0x41, 0x22, 0x14, 0x08, - 0x02, 0x01, 0x59, 0x09, 0x06, - 0x3E, 0x41, 0x5D, 0x59, 0x4E, - 0x7C, 0x12, 0x11, 0x12, 0x7C, - 0x7F, 0x49, 0x49, 0x49, 0x36, - 0x3E, 0x41, 0x41, 0x41, 0x22, - 0x7F, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x49, 0x49, 0x49, 0x41, - 0x7F, 0x09, 0x09, 0x09, 0x01, - 0x3E, 0x41, 0x41, 0x51, 0x73, - 0x7F, 0x08, 0x08, 0x08, 0x7F, - 0x00, 0x41, 0x7F, 0x41, 0x00, - 0x20, 0x40, 0x41, 0x3F, 0x01, - 0x7F, 0x08, 0x14, 0x22, 0x41, - 0x7F, 0x40, 0x40, 0x40, 0x40, - 0x7F, 0x02, 0x1C, 0x02, 0x7F, - 0x7F, 0x04, 0x08, 0x10, 0x7F, - 0x3E, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x09, 0x09, 0x09, 0x06, - 0x3E, 0x41, 0x51, 0x21, 0x5E, - 0x7F, 0x09, 0x19, 0x29, 0x46, - 0x26, 0x49, 0x49, 0x49, 0x32, - 0x03, 0x01, 0x7F, 0x01, 0x03, - 0x3F, 0x40, 0x40, 0x40, 0x3F, - 0x1F, 0x20, 0x40, 0x20, 0x1F, - 0x3F, 0x40, 0x38, 0x40, 0x3F, - 0x63, 0x14, 0x08, 0x14, 0x63, - 0x03, 0x04, 0x78, 0x04, 0x03, - 0x61, 0x59, 0x49, 0x4D, 0x43, - 0x00, 0x7F, 0x41, 0x41, 0x41, - 0x02, 0x04, 0x08, 0x10, 0x20, - 0x00, 0x41, 0x41, 0x41, 0x7F, - 0x04, 0x02, 0x01, 0x02, 0x04, - 0x40, 0x40, 0x40, 0x40, 0x40, - 0x00, 0x03, 0x07, 0x08, 0x00, - 0x20, 0x54, 0x54, 0x78, 0x40, - 0x7F, 0x28, 0x44, 0x44, 0x38, - 0x38, 0x44, 0x44, 0x44, 0x28, - 0x38, 0x44, 0x44, 0x28, 0x7F, - 0x38, 0x54, 0x54, 0x54, 0x18, - 0x00, 0x08, 0x7E, 0x09, 0x02, - 0x18, 0xA4, 0xA4, 0x9C, 0x78, - 0x7F, 0x08, 0x04, 0x04, 0x78, - 0x00, 0x44, 0x7D, 0x40, 0x00, - 0x20, 0x40, 0x40, 0x3D, 0x00, - 0x7F, 0x10, 0x28, 0x44, 0x00, - 0x00, 0x41, 0x7F, 0x40, 0x00, - 0x7C, 0x04, 0x78, 0x04, 0x78, - 0x7C, 0x08, 0x04, 0x04, 0x78, - 0x38, 0x44, 0x44, 0x44, 0x38, - 0xFC, 0x18, 0x24, 0x24, 0x18, - 0x18, 0x24, 0x24, 0x18, 0xFC, - 0x7C, 0x08, 0x04, 0x04, 0x08, - 0x48, 0x54, 0x54, 0x54, 0x24, - 0x04, 0x04, 0x3F, 0x44, 0x24, - 0x3C, 0x40, 0x40, 0x20, 0x7C, - 0x1C, 0x20, 0x40, 0x20, 0x1C, - 0x3C, 0x40, 0x30, 0x40, 0x3C, - 0x44, 0x28, 0x10, 0x28, 0x44, - 0x4C, 0x90, 0x90, 0x90, 0x7C, - 0x44, 0x64, 0x54, 0x4C, 0x44, - 0x00, 0x08, 0x36, 0x41, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, - 0x00, 0x41, 0x36, 0x08, 0x00, - 0x02, 0x01, 0x02, 0x04, 0x02, - 0x3C, 0x26, 0x23, 0x26, 0x3C, - 0x1E, 0xA1, 0xA1, 0x61, 0x12, - 0x3A, 0x40, 0x40, 0x20, 0x7A, - 0x38, 0x54, 0x54, 0x55, 0x59, - 0x21, 0x55, 0x55, 0x79, 0x41, - 0x21, 0x54, 0x54, 0x78, 0x41, - 0x21, 0x55, 0x54, 0x78, 0x40, - 0x20, 0x54, 0x55, 0x79, 0x40, - 0x0C, 0x1E, 0x52, 0x72, 0x12, - 0x39, 0x55, 0x55, 0x55, 0x59, - 0x39, 0x54, 0x54, 0x54, 0x59, - 0x39, 0x55, 0x54, 0x54, 0x58, - 0x00, 0x00, 0x45, 0x7C, 0x41, - 0x00, 0x02, 0x45, 0x7D, 0x42, - 0x00, 0x01, 0x45, 0x7C, 0x40, - 0xF0, 0x29, 0x24, 0x29, 0xF0, - 0xF0, 0x28, 0x25, 0x28, 0xF0, - 0x7C, 0x54, 0x55, 0x45, 0x00, - 0x20, 0x54, 0x54, 0x7C, 0x54, - 0x7C, 0x0A, 0x09, 0x7F, 0x49, - 0x32, 0x49, 0x49, 0x49, 0x32, - 0x32, 0x48, 0x48, 0x48, 0x32, - 0x32, 0x4A, 0x48, 0x48, 0x30, - 0x3A, 0x41, 0x41, 0x21, 0x7A, - 0x3A, 0x42, 0x40, 0x20, 0x78, - 0x00, 0x9D, 0xA0, 0xA0, 0x7D, - 0x39, 0x44, 0x44, 0x44, 0x39, - 0x3D, 0x40, 0x40, 0x40, 0x3D, - 0x3C, 0x24, 0xFF, 0x24, 0x24, - 0x48, 0x7E, 0x49, 0x43, 0x66, - 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, - 0xFF, 0x09, 0x29, 0xF6, 0x20, - 0xC0, 0x88, 0x7E, 0x09, 0x03, - 0x20, 0x54, 0x54, 0x79, 0x41, - 0x00, 0x00, 0x44, 0x7D, 0x41, - 0x30, 0x48, 0x48, 0x4A, 0x32, - 0x38, 0x40, 0x40, 0x22, 0x7A, - 0x00, 0x7A, 0x0A, 0x0A, 0x72, - 0x7D, 0x0D, 0x19, 0x31, 0x7D, - 0x26, 0x29, 0x29, 0x2F, 0x28, - 0x26, 0x29, 0x29, 0x29, 0x26, - 0x30, 0x48, 0x4D, 0x40, 0x20, - 0x38, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x38, - 0x2F, 0x10, 0xC8, 0xAC, 0xBA, - 0x2F, 0x10, 0x28, 0x34, 0xFA, - 0x00, 0x00, 0x7B, 0x00, 0x00, - 0x08, 0x14, 0x2A, 0x14, 0x22, - 0x22, 0x14, 0x2A, 0x14, 0x08, - 0xAA, 0x00, 0x55, 0x00, 0xAA, - 0xAA, 0x55, 0xAA, 0x55, 0xAA, - 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x10, 0x10, 0x10, 0xFF, 0x00, - 0x14, 0x14, 0x14, 0xFF, 0x00, - 0x10, 0x10, 0xFF, 0x00, 0xFF, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x14, 0x14, 0x14, 0xFC, 0x00, - 0x14, 0x14, 0xF7, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x14, 0x14, 0xF4, 0x04, 0xFC, - 0x14, 0x14, 0x17, 0x10, 0x1F, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0x1F, 0x00, - 0x10, 0x10, 0x10, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0xF0, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0xFF, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x14, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x1F, 0x10, 0x17, - 0x00, 0x00, 0xFC, 0x04, 0xF4, - 0x14, 0x14, 0x17, 0x10, 0x17, - 0x14, 0x14, 0xF4, 0x04, 0xF4, - 0x00, 0x00, 0xFF, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0xF7, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x17, 0x14, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0xF4, 0x14, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x00, 0x00, 0x1F, 0x10, 0x1F, - 0x00, 0x00, 0x00, 0x1F, 0x14, - 0x00, 0x00, 0x00, 0xFC, 0x14, - 0x00, 0x00, 0xF0, 0x10, 0xF0, - 0x10, 0x10, 0xFF, 0x10, 0xFF, - 0x14, 0x14, 0x14, 0xFF, 0x14, - 0x10, 0x10, 0x10, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x10, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x38, 0x44, 0x44, 0x38, 0x44, - 0x7C, 0x2A, 0x2A, 0x3E, 0x14, - 0x7E, 0x02, 0x02, 0x06, 0x06, - 0x02, 0x7E, 0x02, 0x7E, 0x02, - 0x63, 0x55, 0x49, 0x41, 0x63, - 0x38, 0x44, 0x44, 0x3C, 0x04, - 0x40, 0x7E, 0x20, 0x1E, 0x20, - 0x06, 0x02, 0x7E, 0x02, 0x02, - 0x99, 0xA5, 0xE7, 0xA5, 0x99, - 0x1C, 0x2A, 0x49, 0x2A, 0x1C, - 0x4C, 0x72, 0x01, 0x72, 0x4C, - 0x30, 0x4A, 0x4D, 0x4D, 0x30, - 0x30, 0x48, 0x78, 0x48, 0x30, - 0xBC, 0x62, 0x5A, 0x46, 0x3D, - 0x3E, 0x49, 0x49, 0x49, 0x00, - 0x7E, 0x01, 0x01, 0x01, 0x7E, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x44, 0x44, 0x5F, 0x44, 0x44, - 0x40, 0x51, 0x4A, 0x44, 0x40, - 0x40, 0x44, 0x4A, 0x51, 0x40, - 0x00, 0x00, 0xFF, 0x01, 0x03, - 0xE0, 0x80, 0xFF, 0x00, 0x00, - 0x08, 0x08, 0x6B, 0x6B, 0x08, - 0x36, 0x12, 0x36, 0x24, 0x36, - 0x06, 0x0F, 0x09, 0x0F, 0x06, - 0x00, 0x00, 0x18, 0x18, 0x00, - 0x00, 0x00, 0x10, 0x10, 0x00, - 0x30, 0x40, 0xFF, 0x01, 0x01, - 0x00, 0x1F, 0x01, 0x01, 0x1E, - 0x00, 0x19, 0x1D, 0x17, 0x12, - 0x00, 0x3C, 0x3C, 0x3C, 0x3C, - 0x00, 0x00, 0x00, 0x00, 0x00, -}; -#endif diff --git a/libraries/TFT/src/utility/keywords.txt b/libraries/TFT/src/utility/keywords.txt deleted file mode 100644 index 9614847d..00000000 --- a/libraries/TFT/src/utility/keywords.txt +++ /dev/null @@ -1,70 +0,0 @@ -####################################### -# Syntax Coloring Map For Adafruit_GFX -# and Adafruit_ST7735 -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -Adafruit_GFX KEYWORD1 -Adafruit_ST7735 KEYWORD1 -PImage KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -drawPixel KEYWORD2 -invertDisplay KEYWORD2 -drawLine KEYWORD2 -drawFastVLine KEYWORD2 -drawFastHLine KEYWORD2 -drawRect KEYWORD2 -fillRect KEYWORD2 -fillScreen KEYWORD2 -drawCircle KEYWORD2 -drawCircleHelper KEYWORD2 -fillCircle KEYWORD2 -fillCircleHelper KEYWORD2 -drawTriangle KEYWORD2 -fillTriangle KEYWORD2 -drawRoundRect KEYWORD2 -fillRoundRect KEYWORD2 -drawBitmap KEYWORD2 -drawChar KEYWORD2 -setCursor KEYWORD2 -setTextColor KEYWORD2 -setTextSize KEYWORD2 -setTextWrap KEYWORD2 -height KEYWORD2 -width KEYWORD2 -setRotation KEYWORD2 -getRotation KEYWORD2 - - - -newColor KEYWORD2 -background KEYWORD2 -fill KEYWORD2 -noFill KEYWORD2 -stroke KEYWORD2 -noStroke KEYWORD2 -text KEYWORD2 -textWrap KEYWORD2 -textSize KEYWORD2 -circle KEYWORD2 -point KEYWORD2 -quad KEYWORD2 -rect KEYWORD2 -triangle KEYWORD2 -loadImage KEYWORD2 -image KEYWORD2 - -draw KEYWORD2 -isValid KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - From 4d1014ff2b89a88f9605e2cb7f75bbe7bd0691e4 Mon Sep 17 00:00:00 2001 From: russmcinnis Date: Wed, 13 Apr 2016 11:10:56 -0600 Subject: [PATCH 027/222] check pin range first thing in pinMode(), digitalWrite() and digitalRead() Signed-off-by: russmcinnis --- cores/arduino/wiring_digital.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 6fdc0758..73c4fa76 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -26,6 +26,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA void pinMode( uint8_t pin, uint8_t mode ) { + if (pin >= NUM_DIGITAL_PINS) return; + PinDescription *p = &g_APinDescription[pin]; if (mode == OUTPUT) { @@ -60,9 +62,9 @@ void pinMode( uint8_t pin, uint8_t mode ) void digitalWrite( uint8_t pin, uint8_t val ) { - PinDescription *p = &g_APinDescription[pin]; - if (pin >= NUM_DIGITAL_PINS) return; + + PinDescription *p = &g_APinDescription[pin]; if (!p->ulInputMode) { if (p->ulGPIOType == SS_GPIO) { @@ -89,9 +91,9 @@ void digitalWrite( uint8_t pin, uint8_t val ) int digitalRead( uint8_t pin ) { - PinDescription *p = &g_APinDescription[pin]; - if (pin >= NUM_DIGITAL_PINS) return LOW; + + PinDescription *p = &g_APinDescription[pin]; if (p->ulGPIOType == SS_GPIO) { From 7bd93b3baf802481282e32240fcfc1f941e36561 Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Thu, 14 Apr 2016 15:46:58 -0700 Subject: [PATCH 028/222] Jira-584: String constructor create floating point string with incorrect number of decimal places. --- cores/arduino/stdlib_noniso.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 89f4f1d5..53225e91 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -202,14 +202,11 @@ char * dtostrf(double number, unsigned char width, unsigned char prec, char *s) // Print the decimal point, but only if there are digits beyond if (prec > 0) { - *out = '.'; - ++out; - prec--; + *out++ = '.'; // Copy character by character to 'out' string for (unsigned char decShift = prec; decShift > 0; decShift--) { remainder *= 10.0; - sprintf(out, "%d", (int)remainder); - out++; + out += sprintf(out, "%d", (int)remainder); remainder -= (double)(int)remainder; } } From 212dae55ea664d1bd92ad175615a49bec7d1bc4f Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 5 Apr 2016 09:50:36 -0400 Subject: [PATCH 029/222] Sync avr/pgmspace.h entries with SAMD core --- cores/arduino/avr/pgmspace.h | 57 ++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/cores/arduino/avr/pgmspace.h b/cores/arduino/avr/pgmspace.h index c7d078e7..8e531990 100644 --- a/cores/arduino/avr/pgmspace.h +++ b/cores/arduino/avr/pgmspace.h @@ -41,28 +41,79 @@ typedef int16_t prog_int16_t; typedef uint16_t prog_uint16_t; typedef int32_t prog_int32_t; typedef uint32_t prog_uint32_t; +typedef int64_t prog_int64_t; +typedef uint64_t prog_uint64_t; -#define memcpy_P(dest, src, num) memcpy((dest), (src), (num)) -#define strcpy_P(dest, src) strcpy((dest), (src)) +typedef const void* int_farptr_t; +typedef const void* uint_farptr_t; + +#define memchr_P(s, c, n) memchr((s), (c), (n)) +#define memcmp_P(s1, s2, n) memcmp((s1), (s2), (n)) +#define memccpy_P(dest, src, c, n) memccpy((dest), (src), (c), (n)) +#define memcpy_P(dest, src, n) memcpy((dest), (src), (n)) +#define memmem_P(haystack, haystacklen, needle, needlelen) memmem((haystack), (haystacklen), (needle), (needlelen)) +#define memrchr_P(s, c, n) memrchr((s), (c), (n)) #define strcat_P(dest, src) strcat((dest), (src)) +#define strchr_P(s, c) strchr((s), (c)) +#define strchrnul_P(s, c) strchrnul((s), (c)) #define strcmp_P(a, b) strcmp((a), (b)) +#define strcpy_P(dest, src) strcpy((dest), (src)) +#define strcasecmp_P(s1, s2) strcasecmp((s1), (s2)) +#define strcasestr_P(haystack, needle) strcasestr((haystack), (needle)) +#define strcspn_P(s, accept) strcspn((s), (accept)) +#define strlcat_P(s1, s2, n) strlcat((s1), (s2), (n)) +#define strlcpy_P(s1, s2, n) strlcpy((s1), (s2), (n)) +#define strlen_P(a) strlen((a)) +#define strnlen_P(s, n) strnlen((s), (n)) +#define strncmp_P(s1, s2, n) strncmp((s1), (s2), (n)) +#define strncasecmp_P(s1, s2, n) strncasecmp((s1), (s2), (n)) +#define strncat_P(s1, s2, n) strncat((s1), (s2), (n)) +#define strncpy_P(s1, s2, n) strncpy((s1), (s2), (n)) +#define strpbrk_P(s, accept) strpbrk((s), (accept)) +#define strrchr_P(s, c) strrchr((s), (c)) +#define strsep_P(sp, delim) strsep((sp), (delim)) +#define strspn_P(s, accept) strspn((s), (accept)) #define strstr_P(a, b) strstr((a), (b)) -#define strlen_P(s) strlen((const char *)(s)) +#define strtok_P(s, delim) strtok((s), (delim)) +#define strtok_rP(s, delim, last) strtok((s), (delim), (last)) + +#define strlen_PF(a) strlen((a)) +#define strnlen_PF(src, len) strnlen((src), (len)) +#define memcpy_PF(dest, src, len) memcpy((dest), (src), (len)) +#define strcpy_PF(dest, src) strcpy((dest), (src)) +#define strncpy_PF(dest, src, len) strncpy((dest), (src), (len)) +#define strcat_PF(dest, src) strcat((dest), (src)) +#define strlcat_PF(dest, src, len) strlcat((dest), (src), (len)) +#define strncat_PF(dest, src, len) strncat((dest), (src), (len)) +#define strcmp_PF(s1, s2) strcmp((s1), (s2)) +#define strncmp_PF(s1, s2, n) strncmp((s1), (s2), (n)) +#define strcasecmp_PF(s1, s2) strcasecmp((s1), (s2)) +#define strncasecmp_PF(s1, s2, n) strncasecmp((s1), (s2), (n)) +#define strstr_PF(s1, s2) strstr((s1), (s2)) +#define strlcpy_PF(dest, src, n) strlcpy((dest), (src), (n)) +#define memcmp_PF(s1, s2, n) memcmp((s1), (s2), (n)) + #define sprintf_P(s, f, ...) sprintf((s), (f), __VA_ARGS__) #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) #define pgm_read_word(addr) (*(const unsigned short *)(addr)) #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) #define pgm_read_float(addr) (*(const float *)(addr)) +#define pgm_read_ptr(addr) (*(const void *)(addr)) #define pgm_read_byte_near(addr) pgm_read_byte(addr) #define pgm_read_word_near(addr) pgm_read_word(addr) #define pgm_read_dword_near(addr) pgm_read_dword(addr) #define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) + #define pgm_read_byte_far(addr) pgm_read_byte(addr) #define pgm_read_word_far(addr) pgm_read_word(addr) #define pgm_read_dword_far(addr) pgm_read_dword(addr) #define pgm_read_float_far(addr) pgm_read_float(addr) +#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) + +#define pgm_get_far_address(addr) (&(addr)) #endif // __PGMSPACE_H_ From f43789e71bcc9c7d8181aec61c48eed3a9683cba Mon Sep 17 00:00:00 2001 From: jysholar Date: Tue, 26 Apr 2016 12:25:01 -0600 Subject: [PATCH 030/222] Jira-560, getInterruptStatus(...) should return type of bool --- libraries/CurieIMU/src/CurieIMU.cpp | 2 +- libraries/CurieIMU/src/CurieIMU.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index ce50a791..12141325 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -1504,7 +1504,7 @@ bool CurieIMUClass::interruptsEnabled(int feature) } } -int CurieIMUClass::getInterruptStatus(int feature) +bool CurieIMUClass::getInterruptStatus(int feature) { switch (feature) { case CURIE_IMU_FREEFALL: diff --git a/libraries/CurieIMU/src/CurieIMU.h b/libraries/CurieIMU/src/CurieIMU.h index d269f708..7f6c6968 100644 --- a/libraries/CurieIMU/src/CurieIMU.h +++ b/libraries/CurieIMU/src/CurieIMU.h @@ -180,7 +180,7 @@ class CurieIMUClass : public BMI160Class { void noInterrupts(int feature); bool interruptsEnabled(int feature); - int getInterruptStatus(int feature); + bool getInterruptStatus(int feature); CurieIMUStepMode getStepDetectionMode(); void setStepDetectionMode(int mode); From 2bac6d3432033197ffc23c6da96ddd99054271f9 Mon Sep 17 00:00:00 2001 From: Calvin Park Date: Mon, 2 May 2016 15:59:10 -0700 Subject: [PATCH 031/222] Fixed the license file to LGPLv2.1 --- LICENSE | 658 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 414 insertions(+), 244 deletions(-) diff --git a/LICENSE b/LICENSE index d159169d..48d4c070 100644 --- a/LICENSE +++ b/LICENSE @@ -1,221 +1,400 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - a) You must cause the modified files to carry prominent notices + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, +identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of +on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. +entire whole, and thus to each and every part regardless of who wrote +it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or -collective works based on the Program. +collective works based on the Library. -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not compelled to copy the source along with the object code. - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are +distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying -the Program or works based on it. +the Library or works based on it. - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to +You are not responsible for enforcing compliance by third parties with this License. - 7. If, as a consequence of a court judgment or allegation of patent + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. +refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other +apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is +integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that @@ -226,114 +405,105 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - 8. If the distribution and/or use of the Program is restricted in + 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. NO WARRANTY - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - + Copyright (C) - 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 2 of the License, or - (at your option) any later version. + 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 program is distributed in the hope that it will be useful, + 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. + 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 General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + 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 St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 + , 1 April 1990 Ty Coon, President of Vice -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +That's all there is to it! + From 9f880240e6cb1deba4c8bd3f296dff4eb5a54929 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Thu, 28 Apr 2016 15:33:58 -0700 Subject: [PATCH 032/222] Updating compile command and driver lib for new toolchain Signed-off-by: Brian Baltz --- platform.txt | 8 ++++---- system/libarc32_arduino101/bootcode/init.S | 5 +++++ variants/arduino_101/libarc32drv_arduino101.a | Bin 434800 -> 431040 bytes 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/platform.txt b/platform.txt index 2b2a2258..0f20ff62 100644 --- a/platform.txt +++ b/platform.txt @@ -14,12 +14,12 @@ compiler.prefix=arc-elf32 compiler.path={runtime.tools.arc-elf32.path}/bin/ compiler.c.cmd=arc-elf32-gcc -compiler.c.flags=-c -mARCv2EM -mav2em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ +compiler.c.flags=-c -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ compiler.c.elf.cmd=arc-elf32-gcc -compiler.c.elf.flags=-nostartfiles -nodefaultlibs -nostdlib -static -Wl,-X -Wl,-N -Wl,-mARCv2EM -Wl,-marcelf -Wl,--gc-sections +compiler.c.elf.flags=-nostartfiles -nodefaultlibs -nostdlib -static -Wl,-X -Wl,-N -Wl,-mcpu=quarkse_em -Wl,-marcelf -Wl,--gc-sections compiler.S.flags=-c -g -x assembler-with-cpp compiler.cpp.cmd=arc-elf32-g++ -compiler.cpp.flags=-c -mARCv2EM -mav2em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -fno-rtti -fno-exceptions -D__ARDUINO_ARC__ -std=c++11 +compiler.cpp.flags=-c -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -fno-rtti -fno-exceptions -D__ARDUINO_ARC__ -std=c++11 compiler.ar.cmd=arc-elf32-ar compiler.ar.flags=rcs compiler.objcopy.cmd=arc-elf32-objcopy @@ -68,7 +68,7 @@ recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -D recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}" ## Combine gc-sections, archives, and objects -recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" "-L{build.variant.path}" -Wl,--whole-archive "-l{build.variant_system_lib}" -Wl,--no-whole-archive -Wl,--start-group "-l{build.variant_system_lib}" -lc -lm -lgcc {object_files} "{build.path}/{archive_file}" +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" "-L{build.variant.path}" -Wl,--whole-archive "-l{build.variant_system_lib}" -Wl,--no-whole-archive -Wl,--start-group "-l{build.variant_system_lib}" -lnsim -lc -lm -lgcc {object_files} "{build.path}/{archive_file}" ## Create output (.bin file) recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" diff --git a/system/libarc32_arduino101/bootcode/init.S b/system/libarc32_arduino101/bootcode/init.S index 6b0aeea6..28aab7d6 100644 --- a/system/libarc32_arduino101/bootcode/init.S +++ b/system/libarc32_arduino101/bootcode/init.S @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .globl _do_fault .type _do_fault,%function +.globl _exit_halt +.type _exit_halt,%function + .globl _do_isr .type _do_isr,%function @@ -57,6 +60,7 @@ _do_reset: */ .balign 4 _do_fault: +_exit_halt: /* Set halt flag */ flag 0x01 nop @@ -86,3 +90,4 @@ _do_isr: nop rtie + diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index ae7eb78dbcd4243dfff8e3b1c7838c4b04325527..1228a153c301ec688e2d61b8eb9e648378c706c4 100644 GIT binary patch literal 431040 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 z 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

cuv2C&?!y%Gy~4O+o(acxl{`G>fbk^e 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 K1o{AYj5nK*JkEto0C*0FgWnISGPQK&7o# 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 i7tmrEh?5fI8CqP(HUJx>F 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

A3T$=p>s%Ccld+W{qo%)311Sc7N~c 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 OX_$FMlDB7+DDz(ojB9!T From eb0cf4f1ceaa0fc4220adcc726063e17934eee3e Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 4 May 2016 10:28:22 +0200 Subject: [PATCH 033/222] Add SERIAL_PORT_USBVIRTUAL and SerialUSB macros This is needed to ensure compatibility with YunShield sketches asas --- variants/arduino_101/variant.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/variants/arduino_101/variant.h b/variants/arduino_101/variant.h index 3b1fa599..ed53a179 100644 --- a/variants/arduino_101/variant.h +++ b/variants/arduino_101/variant.h @@ -202,10 +202,13 @@ void CDCSerial_bytes_sent(uint32_t num); // SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX // pins are NOT connected to anything by default. #define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_USBVIRTUAL Serial #define SERIAL_PORT_HARDWARE_OPEN Serial1 #define SERIAL_PORT_HARDWARE Serial1 #define SERIAL_PORT_HARDWARE1 Serial1 +#define SerialUSB SERIAL_PORT_USBVIRTUAL + extern uint32_t sizeof_g_APinDescription; #endif /* _VARIANT_ARDUINO_101_X_ */ From 434fcd49ddcae18726b8196153baf0a68882b55e Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Tue, 10 May 2016 11:41:19 -0700 Subject: [PATCH 034/222] README.md: clean up and add "support" section Break long lines to be <= 80 chars, where possible, and add a new section to guide users to the appropriate place for support (Arduino forum for product support, issue tracker for bugs & features). --- README.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 01c32016..9bde6e77 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,44 @@ The contents of this repo is distributed through releases in Arduino IDE. If you wish to use the latest **untested** changes, follow these instructions. 1. Install the latest `Intel Curie Boards by Intel` from `Boards Manager` -2. Download the [latest snapshot](https://github.com/01org/corelibs-arduino101/archive/master.zip) of this repo +2. Download the [latest snapshot](https://github.com/01org/corelibs-arduino101/archive/master.zip) + of this repo 3. Shut down the IDE 4. Go to Arduino15 directory * Windows: `C:\Users\\AppData\Roaming\Arduino15` * OS X: `~/Library/Arduino15` * Linux: `~/.arduino15` 5. Go to `packages/Intel/hardware/arc32//` -6. Delete the content of the directory from step 5, and replace it with the content of the "corelibs-arduino101-master" folder in the zip from step 2. +6. Delete the content of the directory from step 5, and replace it with the + content of the "corelibs-arduino101-master" folder in the zip from step 2. -Future upgrades may fail since the internal contents were modified by hand. In order to recover, shut down the IDE, delete the entire `Arduino15` directory, then restart the IDE. +Future upgrades may fail since the internal contents were modified by hand. In +order to recover, shut down the IDE, delete the entire `Arduino15` directory, +then restart the IDE. + +# Support & Issues + +If you have found a bug, or you believe a new feature should be added, please +use the Github issue tracker (click "Issues" above) to provide details about +the bug or feature. If you need product support (e.g. have a question about / +are having problems with the Arduino IDE or the Arduino API), please direct +them to the [support forum](https://forum.arduino.cc/index.php?board=103). + +## Examples of things that should go in the Issue tracker + +> "I noticed that your DoSomeThing library doesn't support all the same +> modes as the library from SomeOtherGuy: https://link-to-relevant-thing.com +> Can you add support for these modes?" + +> "If I run example sketch X on an Arduino 101 board, I get result Y. But if I +> run the same sketch on an Arduino UNO board, I get result Z. This looks like +> a bug to me." + +## Examples of things that should go in the support forum + +> "I'm having trouble downloading the Arduino 101 boards package in the Arduino +> IDE Boards Manager" + +> "How do I use this library?" + +> "I can't get this example sketch to work. What am I doing wrong?" From cdd2989b4297c10c8759de408ccb021f0874763a Mon Sep 17 00:00:00 2001 From: jysholar Date: Mon, 9 May 2016 12:48:48 -0600 Subject: [PATCH 035/222] CurieIMU tap/double example, JIRA-508 --- .../CurieIMU/examples/TapDetect/TapDetect.ino | 23 +++--- .../TapDoubleDetect/TapDoubleDetect.ino | 70 +++++++++++++++++++ 2 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino diff --git a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino index 2ff8b3c0..abe21ae0 100644 --- a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino +++ b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino @@ -37,13 +37,10 @@ void setup() { // Reduce threshold to allow detection of weaker taps (>= 750mg) CurieIMU.setDetectionThreshold(CURIE_IMU_TAP, 750); // (750mg) - // Set the time window for 2 taps to be registered as a double-tap (<= 250 milliseconds) - CurieIMU.setDetectionDuration(CURIE_IMU_DOUBLE_TAP, 250); - // Enable Double-Tap detection - CurieIMU.interrupts(CURIE_IMU_DOUBLE_TAP); + CurieIMU.interrupts(CURIE_IMU_TAP); - Serial.println("IMU initialisation complete, waiting for events..."); + Serial.println("IMU initialization complete, waiting for events..."); } void loop() { @@ -53,18 +50,18 @@ void loop() { static void eventCallback() { - if (CurieIMU.getInterruptStatus(CURIE_IMU_DOUBLE_TAP)) { + if (CurieIMU.getInterruptStatus(CURIE_IMU_TAP)) { if (CurieIMU.tapDetected(X_AXIS, NEGATIVE)) - Serial.println("Double Tap detected on negative X-axis"); + Serial.println("Tap detected on negative X-axis"); if (CurieIMU.tapDetected(X_AXIS, POSITIVE)) - Serial.println("Double Tap detected on positive X-axis"); + Serial.println("Tap detected on positive X-axis"); if (CurieIMU.tapDetected(Y_AXIS, NEGATIVE)) - Serial.println("Double Tap detected on negative Y-axis"); + Serial.println("Tap detected on negative Y-axis"); if (CurieIMU.tapDetected(Y_AXIS, POSITIVE)) - Serial.println("Double Tap detected on positive Y-axis"); + Serial.println("Tap detected on positive Y-axis"); if (CurieIMU.tapDetected(Z_AXIS, NEGATIVE)) - Serial.println("Double Tap detected on negative Z-axis"); + Serial.println("Tap detected on negative Z-axis"); if (CurieIMU.tapDetected(Z_AXIS, POSITIVE)) - Serial.println("Double Tap detected on positive Z-axis"); + Serial.println("Tap detected on positive Z-axis"); } -} +} \ No newline at end of file diff --git a/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino new file mode 100644 index 00000000..be7476a5 --- /dev/null +++ b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino @@ -0,0 +1,70 @@ +/* + Copyright (c) 2015 Intel Corporation. All rights reserved. + + 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 + +*/ + +/* + This sketch example demonstrates how the BMI160 accelerometer on the + Intel(R) Curie(TM) module can be used to detect tap events +*/ + +#include "CurieIMU.h" + +void setup() { + Serial.begin(9600); + + // Initialise the IMU + CurieIMU.begin(); + CurieIMU.attachInterrupt(eventCallback); + + // Increase Accelerometer range to allow detection of stronger taps (< 4g) + CurieIMU.setAccelerometerRange(4); + + // Reduce threshold to allow detection of weaker taps (>= 750mg) + CurieIMU.setDetectionThreshold(CURIE_IMU_DOUBLE_TAP, 750); // (750mg) + + // Set the quite time window for 2 taps to be registered as a double-tap (Gap time between taps <= 1000 milliseconds) + CurieIMU.setDetectionDuration(CURIE_IMU_DOUBLE_TAP, 1000); + + // Enable Double-Tap detection + CurieIMU.interrupts(CURIE_IMU_DOUBLE_TAP); + + Serial.println("IMU initialization complete, waiting for events..."); +} + +void loop() { + // nothing happens in the loop because all the action happens + // in the callback function. +} + +static void eventCallback() +{ + if (CurieIMU.getInterruptStatus(CURIE_IMU_DOUBLE_TAP)) { + if (CurieIMU.tapDetected(X_AXIS, NEGATIVE)) + Serial.println("Double Tap detected on negative X-axis"); + if (CurieIMU.tapDetected(X_AXIS, POSITIVE)) + Serial.println("Double Tap detected on positive X-axis"); + if (CurieIMU.tapDetected(Y_AXIS, NEGATIVE)) + Serial.println("Double Tap detected on negative Y-axis"); + if (CurieIMU.tapDetected(Y_AXIS, POSITIVE)) + Serial.println("Double Tap detected on positive Y-axis"); + if (CurieIMU.tapDetected(Z_AXIS, NEGATIVE)) + Serial.println("Double Tap detected on negative Z-axis"); + if (CurieIMU.tapDetected(Z_AXIS, POSITIVE)) + Serial.println("Double Tap detected on positive Z-axis"); + } +} \ No newline at end of file From 2b5a0402af9486f527805124a5ef937cbfb89ee1 Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Fri, 6 May 2016 16:39:36 -0700 Subject: [PATCH 036/222] Bug fixed: CurieBle library, class BLECharacteristic allocates memory using an incorrect variable which may result in memory corruption if the memory size is bigger than 16 bytes. --- libraries/CurieBLE/src/BLECharacteristic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/CurieBLE/src/BLECharacteristic.cpp b/libraries/CurieBLE/src/BLECharacteristic.cpp index a42b5f7b..a6c46c07 100644 --- a/libraries/CurieBLE/src/BLECharacteristic.cpp +++ b/libraries/CurieBLE/src/BLECharacteristic.cpp @@ -37,7 +37,7 @@ BLECharacteristic::BLECharacteristic(const char* uuid, _presentation_format(NULL) { _value_size = maxLength > BLE_MAX_ATTR_DATA_LEN ? BLE_MAX_ATTR_DATA_LEN : maxLength; - _value = (unsigned char*)malloc(_value_length); + _value = (unsigned char*)malloc(_value_size); memset(_event_handlers, 0, sizeof(_event_handlers)); } From 2bea587379b0e78d4006db13e4c9bdf4482637c0 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Mon, 25 Apr 2016 15:36:38 -0600 Subject: [PATCH 037/222] JIRA-550 Retain unstripped ELF file for debugging Signed-off-by: Brian Baltz --- platform.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform.txt b/platform.txt index 0f20ff62..9cec154c 100644 --- a/platform.txt +++ b/platform.txt @@ -70,6 +70,10 @@ recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compil ## Combine gc-sections, archives, and objects recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" "-L{build.variant.path}" -Wl,--whole-archive "-l{build.variant_system_lib}" -Wl,--no-whole-archive -Wl,--start-group "-l{build.variant_system_lib}" -lnsim -lc -lm -lgcc {object_files} "{build.path}/{archive_file}" +## Save output with debug symbols (.debug.elf file) +recipe.hooks.objcopy.preobjcopy.1.pattern=cp -f "{build.path}/{build.project_name}.elf" "{build.path}/../arduino101_sketch.debug.elf" +recipe.hooks.objcopy.preobjcopy.1.pattern.windows=cmd /C copy /y "{build.path}\{build.project_name}.elf" "{build.path}\..\arduino101_sketch.debug.elf" + ## Create output (.bin file) recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" From 2bb742afd2e8cf0a3708b3b50a94089b5b39a3a8 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Thu, 12 May 2016 11:15:04 -0700 Subject: [PATCH 038/222] Add support for SPI1 device to SPIClass SPI1 can now be used (SPI1.begin()) to access the SPI device connected to the Arduino 101's on-board SPI flash device --- libraries/SPI/src/SPI.cpp | 39 ++++++++++--------- libraries/SPI/src/SPI.h | 59 +++++++++++++++++++++-------- libraries/SPI/src/SPI_registers.h | 11 +++--- variants/arduino_101/pins_arduino.h | 2 +- variants/arduino_101/variant.cpp | 1 + 5 files changed, 72 insertions(+), 40 deletions(-) mode change 100644 => 100755 libraries/SPI/src/SPI.cpp mode change 100644 => 100755 libraries/SPI/src/SPI.h mode change 100644 => 100755 libraries/SPI/src/SPI_registers.h diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp old mode 100644 new mode 100755 index 9f24b834..e4ca4841 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -18,30 +18,32 @@ */ #include "SPI.h" -SPIClass SPI; +SPIClass SPI(SPIDEV_1); +SPIClass SPI1(SPIDEV_0); void SPIClass::setClockDivider(uint8_t clockDiv) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Set SPI Clock Divider */ - SPI1_M_REG_VAL(BAUDR) = clockDiv & SPI_CLOCK_MASK; + SPI_M_REG_VAL(spi_addr, BAUDR) = clockDiv & SPI_CLOCK_MASK; /* re-enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } void SPIClass::setDataMode(uint8_t dataMode) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Set frame size, bus mode and transfer mode */ - SPI1_M_REG_VAL(CTRL0) = (SPI1_M_REG_VAL(CTRL0) & ~(SPI_MODE_MASK)) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); + SPI_M_REG_VAL(spi_addr, CTRL0) = (SPI_M_REG_VAL(spi_addr, CTRL0) + & ~(SPI_MODE_MASK)) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* re-enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } void SPIClass::begin() @@ -60,29 +62,30 @@ void SPIClass::begin() // Set SS to high so a connected chip will be "deselected" by default // TODO - confirm that data register is updated even if pin is set as input - digitalWrite(SS, HIGH); + digitalWrite(ss_gpio, 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); + pinMode(ss_gpio, OUTPUT); /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Enable clock to peripheral */ - MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) |= ENABLE_SPI_MASTER_1; + MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) |= enable_val; /* Configure defaults for clock divider, frame size and data mode */ - SPI1_M_REG_VAL(BAUDR) = SPI_CLOCK_DIV4; - SPI1_M_REG_VAL(CTRL0) = (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); + SPI_M_REG_VAL(spi_addr, BAUDR) = SPI_CLOCK_DIV4; + SPI_M_REG_VAL(spi_addr, CTRL0) = + (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); /* Disable interrupts */ - SPI1_M_REG_VAL(IMR) = SPI_DISABLE_INT; /* Enable at least one slave device (mandatory, though SS signals are unused) */ - SPI1_M_REG_VAL(SER) = 0x1; + SPI_M_REG_VAL(spi_addr, IMR) = SPI_DISABLE_INT; + SPI_M_REG_VAL(spi_addr, SER) = 0x1; /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; /* Set SoC pin mux configuration */ SET_PIN_MODE(g_APinDescription[MOSI].ulSocPin, SPI_MUX_MODE); @@ -104,8 +107,8 @@ void SPIClass::end() { initialized--; // If there are no more references disable SPI if (!initialized) { - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; - MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= DISABLE_SPI_MASTER_1; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; + MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= disable_val; #ifdef SPI_TRANSACTION_MISMATCH_LED inTransactionFlag = 0; #endif diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h old mode 100644 new mode 100755 index 8a96b930..c331624f --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -46,6 +46,11 @@ #define MSBFIRST 1 #endif +#define SPI0_CS 21 +#define SPI1_CS SS + +#define SPIDEV_0 0 +#define SPIDEV_1 1 /* For Arduino Uno compatibility, divider values are doubled to provide equivalent clock rates * e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock * The Intel Curie has a 32MHz base clock and a min divider of 2, so max SPI clock is 16MHz @@ -63,6 +68,7 @@ #define SPI_MODE2 0x02 #define SPI_MODE3 0x03 +#define NUM_SPIDEVS 2 class SPISettings { public: SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { @@ -86,7 +92,12 @@ class SPISettings { class SPIClass { public: - SPIClass(void) { initialized = 0; } + SPIClass(int dev) { + spi_addr = spidevs[dev][0]; + enable_val = spidevs[dev][1]; + disable_val = spidevs[dev][2]; + ss_gpio = spidevs[dev][3]; + } // Initialize the SPI library void begin(); @@ -131,14 +142,14 @@ class SPIClass { #endif /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Configure clock divider, frame size and data mode */ - SPI1_M_REG_VAL(BAUDR) = settings.baudr; - SPI1_M_REG_VAL(CTRL0) = settings.ctrl0; + SPI_M_REG_VAL(spi_addr, BAUDR) = settings.baudr; + SPI_M_REG_VAL(spi_addr, CTRL0) = settings.ctrl0; frameSize = SPI_8_BIT; lsbFirst = settings.lsbFirst; /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } // Write to the SPI bus (MOSI pin) and also receive (MISO pin) @@ -186,15 +197,15 @@ class SPIClass { uint32_t transferSize = SPI_FIFO_DEPTH > remaining ? remaining : SPI_FIFO_DEPTH; /* Fill the TX FIFO */ for (uint32_t i = 0; i < transferSize; i++) - SPI1_M_REG_VAL(DR) = *(p + i); + SPI_M_REG_VAL(spi_addr, DR) = *(p + i); remaining -= transferSize; /* Wait for transfer to complete */ - while (SPI1_M_REG_VAL(SR) & SPI_STATUS_BUSY) ; + while (SPI_M_REG_VAL(spi_addr, SR) & SPI_STATUS_BUSY) ; do { - uint32_t rxLevel = SPI1_M_REG_VAL(RXFL); + uint32_t rxLevel = SPI_M_REG_VAL(spi_addr, RXFL); /* Drain the RX FIFO */ for (uint32_t i = 0; i < rxLevel; i++) - *(p + i) = SPI1_M_REG_VAL(DR); + *(p + i) = SPI_M_REG_VAL(spi_addr, DR); p += rxLevel; transferSize -= rxLevel; } while (transferSize); @@ -248,6 +259,10 @@ class SPIClass { void setClockDivider(uint8_t clockDiv); private: + int ss_gpio; + uint32_t spi_addr; + uint32_t enable_val; + uint32_t disable_val; uint32_t initialized; uint32_t interruptMode; // 0=none, 1-7=mask, 8=global uint32_t interruptMask[3]; // which interrupts to mask @@ -260,26 +275,38 @@ class SPIClass { inline void setFrameSize(uint32_t size) { if (frameSize != size) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Configure new frame size */ frameSize = size; - SPI1_M_REG_VAL(CTRL0) = (SPI1_M_REG_VAL(CTRL0) & ~(SPI_FSIZE_MASK)) | ((frameSize << SPI_FSIZE_SHIFT) & SPI_FSIZE_MASK); + SPI_M_REG_VAL(spi_addr, CTRL0) = (SPI_M_REG_VAL(spi_addr, CTRL0) + & ~(SPI_FSIZE_MASK)) | ((frameSize << SPI_FSIZE_SHIFT) + & SPI_FSIZE_MASK); /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } } inline uint32_t singleTransfer(uint32_t data) { /* Write to TX FIFO */ - SPI1_M_REG_VAL(DR) = data; + SPI_M_REG_VAL(spi_addr, DR) = data; /* Wait for transfer to complete */ - while (SPI1_M_REG_VAL(SR) & SPI_STATUS_BUSY) ; - while (SPI1_M_REG_VAL(RXFL) == 0) ; + while (SPI_M_REG_VAL(spi_addr, SR) & SPI_STATUS_BUSY) ; + while (SPI_M_REG_VAL(spi_addr, RXFL) == 0) ; /* Read from RX FIFO */ - return SPI1_M_REG_VAL(DR); + return SPI_M_REG_VAL(spi_addr, DR); } + + void init(); + void set_dev(int dev); + int spidevs[NUM_SPIDEVS][4] = + { + /* base addr. Clk. enable value Clk. disable value SS GPIO */ + {(int)SOC_MST_SPI0_REGISTER_BASE, ENABLE_SPI_MASTER_0, DISABLE_SPI_MASTER_0, SPI0_CS}, + {(int)SOC_MST_SPI1_REGISTER_BASE, ENABLE_SPI_MASTER_1, DISABLE_SPI_MASTER_1, SPI1_CS} + }; }; extern SPIClass SPI; +extern SPIClass SPI1; #endif diff --git a/libraries/SPI/src/SPI_registers.h b/libraries/SPI/src/SPI_registers.h old mode 100644 new mode 100755 index 657de631..3b3823a4 --- a/libraries/SPI/src/SPI_registers.h +++ b/libraries/SPI/src/SPI_registers.h @@ -21,9 +21,8 @@ #include "portable.h" -/* Macro to access SPI1 Master controller register offset */ -#define SPI1_M_REG_VAL(reg) \ - MMIO_REG_VAL_FROM_BASE(SOC_MST_SPI1_REGISTER_BASE, (reg)) +/* Macro to access SPI Master controller register offset */ +#define SPI_M_REG_VAL(base, reg) MMIO_REG_VAL_FROM_BASE(base, (reg)) /* SoC SPI device register offsets */ #define CTRL0 (0x00) /* SoC SPI Control Register 1 */ @@ -55,8 +54,10 @@ #define SPI_FIFO_DEPTH (8UL) -#define ENABLE_SPI_MASTER_1 (0x1 << 15) -#define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) +#define ENABLE_SPI_MASTER_0 (0x1 << 14) +#define DISABLE_SPI_MASTER_0 (~ENABLE_SPI_MASTER_0) +#define ENABLE_SPI_MASTER_1 (0x1 << 15) +#define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) #define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* CLOCK_SPEED in MHz */ diff --git a/variants/arduino_101/pins_arduino.h b/variants/arduino_101/pins_arduino.h index 8e7551a3..631c35cc 100644 --- a/variants/arduino_101/pins_arduino.h +++ b/variants/arduino_101/pins_arduino.h @@ -25,7 +25,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h -#define NUM_DIGITAL_PINS 21 +#define NUM_DIGITAL_PINS 22 #define NUM_ANALOG_INPUTS 6 #define NUM_PWM 4 #define NUM_UARTS 1 diff --git a/variants/arduino_101/variant.cpp b/variants/arduino_101/variant.cpp index 974eb798..0fe85c2d 100644 --- a/variants/arduino_101/variant.cpp +++ b/variants/arduino_101/variant.cpp @@ -83,6 +83,7 @@ PinDescription g_APinDescription[]= { 6, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 14, GPIO_MUX_MODE, INVALID, INVALID, 14, INPUT_MODE }, // Arduino IO18 { 1, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 9, GPIO_MUX_MODE, INVALID, INVALID, 9, INPUT_MODE }, // Arduino IO19 { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 + { 24, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 58, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO21 } ; From 331b2f0152bb90f1c96ee1726e8017db56e51789 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Thu, 12 May 2016 11:18:35 -0700 Subject: [PATCH 039/222] Clean up the SPI files Be consistent about commenting style, and stay below 80 chars where appropriate. --- libraries/SPI/src/SPI.cpp | 30 ++++---- libraries/SPI/src/SPI.h | 109 ++++++++++++++++-------------- libraries/SPI/src/SPI_registers.h | 57 ++++++++-------- 3 files changed, 106 insertions(+), 90 deletions(-) diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index e4ca4841..57644358 100755 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -13,7 +13,7 @@ * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "SPI.h" @@ -48,7 +48,8 @@ void SPIClass::setDataMode(uint8_t dataMode) void SPIClass::begin() { - uint32_t flags = interrupt_lock(); // Protect from a scheduler and prevent transactionBegin + /* Protect from a scheduler and prevent transactionBegin*/ + uint32_t flags = interrupt_lock(); if (!initialized) { interruptMode = 0; interruptMask[0] = 0; @@ -60,13 +61,14 @@ void SPIClass::begin() lsbFirst = false; frameSize = SPI_8_BIT; - // Set SS to high so a connected chip will be "deselected" by default - // TODO - confirm that data register is updated even if pin is set as input + /* Set SS to high so a connected chip will be "deselected" by default. + * TODO - confirm that data register is updated even if pin is set as + * input. */ digitalWrite(ss_gpio, 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). + /* 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_gpio, OUTPUT); /* disable controller */ @@ -81,8 +83,9 @@ void SPIClass::begin() (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); /* Disable interrupts */ - /* Enable at least one slave device (mandatory, though SS signals are unused) */ SPI_M_REG_VAL(spi_addr, IMR) = SPI_DISABLE_INT; + /* Enable at least one slave device (mandatory, though + * SS signals are unused) */ SPI_M_REG_VAL(spi_addr, SER) = 0x1; /* Enable controller */ SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; @@ -96,16 +99,17 @@ void SPIClass::begin() g_APinDescription[SCK].ulPinMode = SPI_MUX_MODE; } - initialized++; // reference count + initialized++; /* reference count */ interrupt_unlock(flags); } void SPIClass::end() { - uint32_t flags = interrupt_lock(); // Protect from a scheduler and prevent transactionBegin - // Decrease the reference counter + /* Protect from a scheduler and prevent transactionBegin */ + uint32_t flags = interrupt_lock(); + /* Decrease the reference counter */ if (initialized) initialized--; - // If there are no more references disable SPI + /* If there are no more references disable SPI */ if (!initialized) { SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= disable_val; @@ -142,7 +146,7 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber) { } void SPIClass::notUsingInterrupt(uint8_t interruptNumber) { - // Once in mode 8 we can't go back to 0 without a proper reference count + /* Once in mode 8 we can't go back to 0 without a proper reference count */ if (interruptMode == 8) return; diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index c331624f..40892da8 100755 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -19,24 +19,25 @@ #include "SPI_registers.h" -// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), -// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +/* SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), + * usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) */ #define SPI_HAS_TRANSACTION 1 -// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +/* SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method */ #define SPI_HAS_NOTUSINGINTERRUPT 1 -// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. -// This way when there is a bug fix you can check this define to alert users -// of your code if it uses better version of this library. -// This also implies everything that SPI_HAS_TRANSACTION as documented above is -// available too. +/* SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. + * This way when there is a bug fix you can check this define to alert users + * of your code if it uses better version of this library. + * This also implies everything that SPI_HAS_TRANSACTION as documented above is + * available too. */ #define SPI_ATOMIC_VERSION 1 -// Uncomment this line to add detection of mismatched begin/end transactions. -// A mismatch occurs if other libraries fail to use SPI.endTransaction() for -// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn -// on if any mismatch is ever detected. +/* Uncomment this line to add detection of mismatched begin/end transactions. + * A mismatch occurs if other libraries fail to use SPI.endTransaction() for + * each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn + * on if any mismatch is ever detected. */ + //#define SPI_TRANSACTION_MISMATCH_LED 5 #ifndef LSBFIRST @@ -51,10 +52,11 @@ #define SPIDEV_0 0 #define SPIDEV_1 1 -/* For Arduino Uno compatibility, divider values are doubled to provide equivalent clock rates - * e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock - * The Intel Curie has a 32MHz base clock and a min divider of 2, so max SPI clock is 16MHz - */ + +/* For Arduino Uno compatibility, divider values are doubled to provide + * equivalent clock rates e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock + * The Intel Curie has a 32MHz base clock and a min divider of 2, so max + * SPI clock is 16MHz */ #define SPI_CLOCK_DIV4 8 #define SPI_CLOCK_DIV16 32 #define SPI_CLOCK_DIV64 128 @@ -69,14 +71,17 @@ #define SPI_MODE3 0x03 #define NUM_SPIDEVS 2 + class SPISettings { public: SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { /* Set frame size, bus mode and transfer mode */ - ctrl0 = (SPI_8_BIT << SPI_FSIZE_SHIFT) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); + ctrl0 = (SPI_8_BIT << SPI_FSIZE_SHIFT) + | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* Set SPI Clock Divider */ baudr = (SPI_BASE_CLOCK / clock) & SPI_CLOCK_MASK; - /* Only MSBFIRST supported in hardware, need to swizzle the bits if LSBFIRST selected */ + /* Only MSBFIRST supported in hardware, need to swizzle the bits if + * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false; } SPISettings() { @@ -99,26 +104,26 @@ class SPIClass { ss_gpio = spidevs[dev][3]; } - // Initialize the SPI library + /* Initialize the SPI library */ void begin(); - // If SPI is used from within an interrupt, this function registers - // that interrupt with the SPI library, so beginTransaction() can - // prevent conflicts. The input interruptNumber is the number used - // with attachInterrupt. If SPI is used from a different interrupt - // (eg, a timer), interruptNumber should be 255. + /* If SPI is used from within an interrupt, this function registers + * that interrupt with the SPI library, so beginTransaction() can + * prevent conflicts. The input interruptNumber is the number used + * with attachInterrupt. If SPI is used from a different interrupt + * (eg, a timer), interruptNumber should be 255. */ void usingInterrupt(uint8_t interruptNumber); - // And this does the opposite. + /* And this does the opposite. */ void notUsingInterrupt(uint8_t interruptNumber); - // Note: the usingInterrupt and notUsingInterrupt functions should - // not to be called from ISR context or inside a transaction. - // For details see: - // https://github.com/arduino/Arduino/pull/2381 - // https://github.com/arduino/Arduino/pull/2449 - - // Before using SPI.transfer() or asserting chip select pins, - // this function is used to gain exclusive access to the SPI bus - // and configure the correct settings. + /* Note: the usingInterrupt and notUsingInterrupt functions should + * not to be called from ISR context or inside a transaction. + * For details see: + * https://github.com/arduino/Arduino/pull/2381 + * https://github.com/arduino/Arduino/pull/2449 */ + + /* Before using SPI.transfer() or asserting chip select pins, + * this function is used to gain exclusive access to the SPI bus + * and configure the correct settings. */ inline void beginTransaction(SPISettings settings) { if (interruptMode > 0) { if (interruptMode < 8) { @@ -152,7 +157,7 @@ class SPIClass { SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } - // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + /* Write to the SPI bus (MOSI pin) and also receive (MISO pin) */ inline uint8_t transfer(uint8_t data) { setFrameSize(SPI_8_BIT); if (lsbFirst) @@ -217,8 +222,8 @@ class SPIClass { } } - // After performing a group of transfers and releasing the chip select - // signal, this function allows others to access the SPI bus + /* After performing a group of transfers and releasing the chip select + * signal, this function allows others to access the SPI bus */ inline void endTransaction(void) { #ifdef SPI_TRANSACTION_MISMATCH_LED if (!inTransactionFlag) { @@ -231,31 +236,35 @@ class SPIClass { if (interruptMode > 0) { if (interruptMode < 8) { if (interruptMode & 1) - CLEAR_ARC_MASK(SS_GPIO_8B0_BASE_ADDR + SS_GPIO_INTMASK, interruptMask[0]); + CLEAR_ARC_MASK(SS_GPIO_8B0_BASE_ADDR + SS_GPIO_INTMASK, + interruptMask[0]); if (interruptMode & 2) - CLEAR_ARC_MASK(SS_GPIO_8B1_BASE_ADDR + SS_GPIO_INTMASK, interruptMask[1]); + CLEAR_ARC_MASK(SS_GPIO_8B1_BASE_ADDR + SS_GPIO_INTMASK, + interruptMask[1]); if (interruptMode & 4) - CLEAR_MMIO_MASK(SOC_GPIO_BASE_ADDR + SOC_GPIO_INTMASK, interruptMask[2]); + CLEAR_MMIO_MASK(SOC_GPIO_BASE_ADDR + SOC_GPIO_INTMASK, + interruptMask[2]); } else { interrupts(); } } } - // Disable the SPI bus + /* Disable the SPI bus */ void end(); - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ inline void setBitOrder(uint8_t bitOrder) { - /* Only MSBFIRST supported in hardware, need to swizzle the bits if LSBFIRST selected */ + /* Only MSBFIRST supported in hardware, need to swizzle the bits if + * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false; } - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ void setDataMode(uint8_t dataMode); - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ void setClockDivider(uint8_t clockDiv); private: @@ -264,8 +273,8 @@ class SPIClass { uint32_t enable_val; uint32_t disable_val; uint32_t initialized; - uint32_t interruptMode; // 0=none, 1-7=mask, 8=global - uint32_t interruptMask[3]; // which interrupts to mask + uint32_t interruptMode; /* 0=none, 1-7=mask, 8=global */ + uint32_t interruptMask[3]; /* which interrupts to mask */ #ifdef SPI_TRANSACTION_MISMATCH_LED uint32_t inTransactionFlag; #endif diff --git a/libraries/SPI/src/SPI_registers.h b/libraries/SPI/src/SPI_registers.h index 3b3823a4..9b8f017c 100755 --- a/libraries/SPI/src/SPI_registers.h +++ b/libraries/SPI/src/SPI_registers.h @@ -13,7 +13,7 @@ * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef _SPI_REGISTERS_H_ @@ -25,44 +25,47 @@ #define SPI_M_REG_VAL(base, reg) MMIO_REG_VAL_FROM_BASE(base, (reg)) /* SoC SPI device register offsets */ -#define CTRL0 (0x00) /* SoC SPI Control Register 1 */ -#define SPIEN (0x08) /* SoC SPI Enable Register */ -#define SER (0x10) /* SoC SPI Slave Enable Register */ -#define BAUDR (0x14) /* SoC SPI Baud Rate Select */ -#define TXFL (0x20) /* SoC SPI Transmit FIFO Level Register */ -#define RXFL (0x24) /* SoC SPI Receive FIFO Level Register */ -#define SR (0x28) /* SoC SPI Status Register */ -#define IMR (0x2C) /* SoC SPI Interrupt Mask Register */ -#define DR (0x60) /* SoC SPI Data Register */ +#define CTRL0 (0x00) /* SoC SPI Control */ +#define SPIEN (0x08) /* SoC SPI Enable */ +#define SER (0x10) /* SoC SPI Slave Enable */ +#define BAUDR (0x14) /* SoC SPI Baud Rate Select */ +#define TXFL (0x20) /* SoC SPI Transmit FIFO Level */ +#define RXFL (0x24) /* SoC SPI Receive FIFO Level */ +#define SR (0x28) /* SoC SPI Status Register */ +#define IMR (0x2C) /* SoC SPI Interrupt Mask */ +#define DR (0x60) /* SoC SPI Data */ /* SPI specific macros */ -#define SPI_DISABLE_INT (0x0) /* Disable SoC SPI Interrupts */ -#define SPI_ENABLE (0x1) /* Enable SoC SPI Device */ -#define SPI_DISABLE (0x0) /* Disable SoC SPI Device */ -#define SPI_STATUS_BUSY (0x1) /* Busy status */ +#define SPI_DISABLE_INT (0x0) /* Disable SoC SPI Interrupts */ +#define SPI_ENABLE (0x1) /* Enable SoC SPI Device */ +#define SPI_DISABLE (0x0) /* Disable SoC SPI Device */ +#define SPI_STATUS_BUSY (0x1) /* Busy status */ -#define SPI_8_BIT (7) /* 8-bit frame size */ -#define SPI_16_BIT (15) /* 16-bit frame size */ -#define SPI_24_BIT (23) /* 24-bit frame size */ -#define SPI_32_BIT (31) /* 32-bit frame size */ +#define SPI_8_BIT (7) /* 8-bit frame size */ +#define SPI_16_BIT (15) /* 16-bit frame size */ +#define SPI_24_BIT (23) /* 24-bit frame size */ +#define SPI_32_BIT (31) /* 32-bit frame size */ -#define SPI_MODE_MASK (0xC0) /* CPOL = bit 7, CPHA = bit 6 on CTRL0 */ -#define SPI_MODE_SHIFT (6) -#define SPI_FSIZE_MASK (0x1F0000) /* Valid frame sizes: 1- 32 bits */ -#define SPI_FSIZE_SHIFT (16) -#define SPI_CLOCK_MASK (0xFFFE) /* Clock divider: any even value in the ragnge 2-65534 */ +#define SPI_MODE_MASK (0xC0) /* CPOL=bit 7, CPHA=bit 6 on CTRL0 */ +#define SPI_MODE_SHIFT (6) +#define SPI_FSIZE_MASK (0x1F0000) /* Valid frame sizes: 1-32 bits */ +#define SPI_FSIZE_SHIFT (16) +#define SPI_CLOCK_MASK (0xFFFE) /* Clock divider: any even value + * in the ragnge 2-65534 */ -#define SPI_FIFO_DEPTH (8UL) +#define SPI_FIFO_DEPTH (8UL) #define ENABLE_SPI_MASTER_0 (0x1 << 14) #define DISABLE_SPI_MASTER_0 (~ENABLE_SPI_MASTER_0) #define ENABLE_SPI_MASTER_1 (0x1 << 15) #define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) -#define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* CLOCK_SPEED in MHz */ + /* CLOCK_SPEED in MHz */ +#define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* Utility function to reverse the bit order of a 32-bit word */ -static inline uint32_t arc32_bit_reverse(register uint32_t src, register uint32_t count) +static inline uint32_t arc32_bit_reverse(register uint32_t src, + register uint32_t count) { register uint32_t dst = 0; /* Copy the specified number of least-significant bits from src to dst, @@ -85,4 +88,4 @@ static inline uint32_t arc32_bit_reverse(register uint32_t src, register uint32_ #define SPI_REVERSE_24(b) arc32_bit_reverse((b), 24) #define SPI_REVERSE_32(b) arc32_bit_reverse((b), 32) -#endif // _SPI_REGISTERS_H_ +#endif /* _SPI_REGISTERS_H_ */ From 8dea7b4a1430dce33870a97fcf0330e0cda4fef3 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Mon, 16 May 2016 10:41:02 -0700 Subject: [PATCH 040/222] Fix SPI clock divider calculation If a clock value greater than the maximum supported is passed (i.e. > 16MHz), the resulting value written to the BAUDR register will be 0 which will disable the serial output clock. Check for this and ensure the value calculated for BAUDR register is never < 2. --- libraries/SPI/src/SPI.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 40892da8..cd37622b 100755 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -80,6 +80,12 @@ class SPISettings { | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* Set SPI Clock Divider */ baudr = (SPI_BASE_CLOCK / clock) & SPI_CLOCK_MASK; + + /* clock value passed is > than max supported; + * set baudr to 2 for max. speed */ + if (baudr == 0) + baudr = 2; + /* Only MSBFIRST supported in hardware, need to swizzle the bits if * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false; From 92818058e83302e478e7cdddd60d1d5568ce9bc5 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Thu, 19 May 2016 10:34:30 -0700 Subject: [PATCH 041/222] Add Paul Stoffregen's SerialFlash library --- libraries/SerialFlash/SerialFlash.h | 132 +++++ libraries/SerialFlash/SerialFlashChip.cpp | 523 ++++++++++++++++++ .../SerialFlash/SerialFlashDirectory.cpp | 393 +++++++++++++ .../examples/CopyFromSD/CopyFromSD.ino | 133 +++++ .../CopyFromSerial/CopyFromSerial.ino | 275 +++++++++ .../EraseEverything/EraseEverything.ino | 80 +++ .../examples/FileWrite/FileWrite.ino | 50 ++ .../examples/ListFiles/ListFiles.ino | 63 +++ .../RawHardwareTest/RawHardwareTest.ino | 501 +++++++++++++++++ libraries/SerialFlash/keywords.txt | 9 + .../util/SerialFlash_directwrite.h | 204 +++++++ 11 files changed, 2363 insertions(+) create mode 100644 libraries/SerialFlash/SerialFlash.h create mode 100644 libraries/SerialFlash/SerialFlashChip.cpp create mode 100644 libraries/SerialFlash/SerialFlashDirectory.cpp create mode 100644 libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino create mode 100644 libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino create mode 100644 libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino create mode 100755 libraries/SerialFlash/examples/FileWrite/FileWrite.ino create mode 100644 libraries/SerialFlash/examples/ListFiles/ListFiles.ino create mode 100644 libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino create mode 100644 libraries/SerialFlash/keywords.txt create mode 100644 libraries/SerialFlash/util/SerialFlash_directwrite.h diff --git a/libraries/SerialFlash/SerialFlash.h b/libraries/SerialFlash/SerialFlash.h new file mode 100644 index 00000000..e56df624 --- /dev/null +++ b/libraries/SerialFlash/SerialFlash.h @@ -0,0 +1,132 @@ +/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory + * https://github.com/PaulStoffregen/SerialFlash + * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com + * + * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. + * Please support PJRC's efforts to develop open source software by purchasing + * Teensy or other genuine PJRC products. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SerialFlash_h_ +#define SerialFlash_h_ + +#include +#include + +class SerialFlashFile; + +class SerialFlashChip +{ +public: + static bool begin(uint8_t pin = 6); + static uint32_t capacity(const uint8_t *id); + static uint32_t blockSize(); + static void sleep(); + static void wakeup(); + static void readID(uint8_t *buf); + static void readSerialNumber(uint8_t *buf); + static void read(uint32_t addr, void *buf, uint32_t len); + static bool ready(); + static void wait(); + static void write(uint32_t addr, const void *buf, uint32_t len); + static void eraseAll(); + static void eraseBlock(uint32_t addr); + + static SerialFlashFile open(const char *filename); + static bool create(const char *filename, uint32_t length, uint32_t align = 0); + static bool createErasable(const char *filename, uint32_t length) { + return create(filename, length, blockSize()); + } + static bool exists(const char *filename); + static bool remove(const char *filename); + static bool remove(SerialFlashFile &file); + static void opendir() { dirindex = 0; } + static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize); +private: + static uint16_t dirindex; // current position for readdir() + static uint8_t flags; // chip features + static uint8_t busy; // 0 = ready + // 1 = suspendable program operation + // 2 = suspendable erase operation + // 3 = busy for realz!! +}; + +extern SerialFlashChip SerialFlash; + + +class SerialFlashFile +{ +public: + SerialFlashFile() : address(0) { + } + operator bool() { + if (address > 0) return true; + return false; + } + uint32_t read(void *buf, uint32_t rdlen) { + if (offset + rdlen > length) { + if (offset >= length) return 0; + rdlen = length - offset; + } + SerialFlash.read(address + offset, buf, rdlen); + offset += rdlen; + return rdlen; + } + uint32_t write(const void *buf, uint32_t wrlen) { + if (offset + wrlen > length) { + if (offset >= length) return 0; + wrlen = length - offset; + } + SerialFlash.write(address + offset, buf, wrlen); + offset += wrlen; + return wrlen; + } + void seek(uint32_t n) { + offset = n; + } + uint32_t position() { + return offset; + } + uint32_t size() { + return length; + } + uint32_t available() { + if (offset >= length) return 0; + return length - offset; + } + void erase(); + void flush() { + } + void close() { + } + uint32_t getFlashAddress() { + return address; + } +protected: + friend class SerialFlashChip; + uint32_t address; // where this file's data begins in the Flash, or zero + uint32_t length; // total length of the data in the Flash chip + uint32_t offset; // current read/write offset in the file + uint16_t dirindex; +}; + + +#endif diff --git a/libraries/SerialFlash/SerialFlashChip.cpp b/libraries/SerialFlash/SerialFlashChip.cpp new file mode 100644 index 00000000..4e467f57 --- /dev/null +++ b/libraries/SerialFlash/SerialFlashChip.cpp @@ -0,0 +1,523 @@ +/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory + * https://github.com/PaulStoffregen/SerialFlash + * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com + * + * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. + * Please support PJRC's efforts to develop open source software by purchasing + * Teensy or other genuine PJRC products. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "SerialFlash.h" +#include "util/SerialFlash_directwrite.h" + +#define CSASSERT() DIRECT_WRITE_LOW(cspin_basereg, cspin_bitmask) +#define CSRELEASE() DIRECT_WRITE_HIGH(cspin_basereg, cspin_bitmask) +#define SPICONFIG SPISettings(50000000, MSBFIRST, SPI_MODE0) + +#if defined(__arc__) +// Use SPI1 on Arduino 101 (accesses chip already on the board) +#define SPIPORT SPI1 +#elif 0 +// Add cases here, if you wish to use other SPI ports... +#else +// Otherwise, use the normal SPI port. +#define SPIPORT SPI +#endif + +uint16_t SerialFlashChip::dirindex = 0; +uint8_t SerialFlashChip::flags = 0; +uint8_t SerialFlashChip::busy = 0; + +static volatile IO_REG_TYPE *cspin_basereg; +static IO_REG_TYPE cspin_bitmask; + +#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address +#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check +#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands +#define FLAG_MULTI_DIE 0x08 // multiple die, don't read cross 32M barrier +#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks +#define FLAG_DIE_MASK 0xC0 // top 2 bits count during multi-die erase + +void SerialFlashChip::wait(void) +{ + uint32_t status; + //Serial.print("wait-"); + while (1) { + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + if (flags & FLAG_STATUS_CMD70) { + // some Micron chips require this different + // command to detect program and erase completion + SPIPORT.transfer(0x70); + status = SPIPORT.transfer(0); + CSRELEASE(); + SPIPORT.endTransaction(); + //Serial.printf("b=%02x.", status & 0xFF); + if ((status & 0x80)) break; + } else { + // all others work by simply reading the status reg + SPIPORT.transfer(0x05); + status = SPIPORT.transfer(0); + CSRELEASE(); + SPIPORT.endTransaction(); + //Serial.printf("b=%02x.", status & 0xFF); + if (!(status & 1)) break; + } + } + busy = 0; + //Serial.println(); +} + +void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len) +{ + uint8_t *p = (uint8_t *)buf; + uint8_t b, f, status, cmd; + + memset(p, 0, len); + f = flags; + SPIPORT.beginTransaction(SPICONFIG); + b = busy; + if (b) { + // read status register ... chip may no longer be busy + CSASSERT(); + if (flags & FLAG_STATUS_CMD70) { + SPIPORT.transfer(0x70); + status = SPIPORT.transfer(0); + if ((status & 0x80)) b = 0; + } else { + SPIPORT.transfer(0x05); + status = SPIPORT.transfer(0); + if (!(status & 1)) b = 0; + } + CSRELEASE(); + if (b == 0) { + // chip is no longer busy :-) + busy = 0; + } else if (b < 3) { + // TODO: this may not work on Spansion chips + // which apparently have 2 different suspend + // commands, for program vs erase + CSASSERT(); + SPIPORT.transfer(0x06); // write enable (Micron req'd) + CSRELEASE(); + delayMicroseconds(1); + cmd = 0x75; //Suspend program/erase for almost all chips + // but Spansion just has to be different for program suspend! + if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85; + CSASSERT(); + SPIPORT.transfer(cmd); // Suspend command + CSRELEASE(); + if (f & FLAG_STATUS_CMD70) { + // Micron chips don't actually suspend until flags read + CSASSERT(); + SPIPORT.transfer(0x70); + do { + status = SPIPORT.transfer(0); + } while (!(status & 0x80)); + CSRELEASE(); + } else { + CSASSERT(); + SPIPORT.transfer(0x05); + do { + status = SPIPORT.transfer(0); + } while ((status & 0x01)); + CSRELEASE(); + } + } else { + // chip is busy with an operation that can not suspend + SPIPORT.endTransaction(); // is this a good idea? + wait(); // should we wait without ending + b = 0; // the transaction?? + SPIPORT.beginTransaction(SPICONFIG); + } + } + do { + uint32_t rdlen = len; + if (f & FLAG_MULTI_DIE) { + if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) { + rdlen = 0x2000000 - (addr & 0x1FFFFFF); + } + } + CSASSERT(); + // TODO: FIFO optimize.... + if (f & FLAG_32BIT_ADDR) { + SPIPORT.transfer(0x03); + SPIPORT.transfer16(addr >> 16); + SPIPORT.transfer16(addr); + } else { + SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255)); + SPIPORT.transfer16(addr); + } + SPIPORT.transfer(p, rdlen); + CSRELEASE(); + p += rdlen; + addr += rdlen; + len -= rdlen; + } while (len > 0); + if (b) { + CSASSERT(); + SPIPORT.transfer(0x06); // write enable (Micron req'd) + CSRELEASE(); + delayMicroseconds(1); + cmd = 0x7A; + if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A; + CSASSERT(); + SPIPORT.transfer(cmd); // Resume program/erase + CSRELEASE(); + } + SPIPORT.endTransaction(); +} + +void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len) +{ + const uint8_t *p = (const uint8_t *)buf; + uint32_t max, pagelen; + + //Serial.printf("WR: addr %08X, len %d\n", addr, len); + do { + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + // write enable command + SPIPORT.transfer(0x06); + CSRELEASE(); + max = 256 - (addr & 0xFF); + pagelen = (len <= max) ? len : max; + //Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen); + delayMicroseconds(1); // TODO: reduce this, but prefer safety first + CSASSERT(); + if (flags & FLAG_32BIT_ADDR) { + SPIPORT.transfer(0x02); // program page command + SPIPORT.transfer16(addr >> 16); + SPIPORT.transfer16(addr); + } else { + SPIPORT.transfer16(0x0200 | ((addr >> 16) & 255)); + SPIPORT.transfer16(addr); + } + addr += pagelen; + len -= pagelen; + do { + SPIPORT.transfer(*p++); + } while (--pagelen > 0); + CSRELEASE(); + busy = 4; + SPIPORT.endTransaction(); + } while (len > 0); +} + +void SerialFlashChip::eraseAll() +{ + if (busy) wait(); + uint8_t id[5]; + readID(id); + //Serial.printf("ID: %02X %02X %02X\n", id[0], id[1], id[2]); + if (id[0] == 0x20 && id[2] >= 0x20 && id[2] <= 0x22) { + // Micron's multi-die chips require special die erase commands + // N25Q512A 20 BA 20 2 dies 32 Mbyte/die 65 nm transitors + // N25Q00AA 20 BA 21 4 dies 32 Mbyte/die 65 nm transitors + // MT25QL02GC 20 BA 22 2 dies 128 Mbyte/die 45 nm transitors + uint8_t die_count = 2; + if (id[2] == 0x21) die_count = 4; + uint8_t die_index = flags >> 6; + //Serial.printf("Micron die erase %d\n", die_index); + flags &= 0x3F; + if (die_index >= die_count) return; // all dies erased :-) + uint8_t die_size = 2; // in 16 Mbyte units + if (id[2] == 0x22) die_size = 8; + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0x06); // write enable command + CSRELEASE(); + delayMicroseconds(1); + CSASSERT(); + // die erase command + SPIPORT.transfer(0xC4); + SPIPORT.transfer16((die_index * die_size) << 8); + SPIPORT.transfer16(0x0000); + CSRELEASE(); + //Serial.printf("Micron erase begin\n"); + flags |= (die_index + 1) << 6; + } else { + // All other chips support the bulk erase command + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + // write enable command + SPIPORT.transfer(0x06); + CSRELEASE(); + delayMicroseconds(1); + CSASSERT(); + // bulk erase command + SPIPORT.transfer(0xC7); + CSRELEASE(); + SPIPORT.endTransaction(); + } + busy = 3; +} + +void SerialFlashChip::eraseBlock(uint32_t addr) +{ + uint8_t f = flags; + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0x06); // write enable command + CSRELEASE(); + delayMicroseconds(1); + CSASSERT(); + if (f & FLAG_32BIT_ADDR) { + SPIPORT.transfer(0xD8); + SPIPORT.transfer16(addr >> 16); + SPIPORT.transfer16(addr); + } else { + SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255)); + SPIPORT.transfer16(addr); + } + CSRELEASE(); + SPIPORT.endTransaction(); + busy = 2; +} + + +bool SerialFlashChip::ready() +{ + uint32_t status; + if (!busy) return true; + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + if (flags & FLAG_STATUS_CMD70) { + // some Micron chips require this different + // command to detect program and erase completion + SPIPORT.transfer(0x70); + status = SPIPORT.transfer(0); + CSRELEASE(); + SPIPORT.endTransaction(); + //Serial.printf("ready=%02x\n", status & 0xFF); + if ((status & 0x80) == 0) return false; + } else { + // all others work by simply reading the status reg + SPIPORT.transfer(0x05); + status = SPIPORT.transfer(0); + CSRELEASE(); + SPIPORT.endTransaction(); + //Serial.printf("ready=%02x\n", status & 0xFF); + if ((status & 1)) return false; + } + busy = 0; + if (flags & 0xC0) { + // continue a multi-die erase + eraseAll(); + return false; + } + return true; +} + + +#define ID0_WINBOND 0xEF +#define ID0_SPANSION 0x01 +#define ID0_MICRON 0x20 +#define ID0_MACRONIX 0xC2 +#define ID0_SST 0xBF + +//#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address +//#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check +//#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands +//#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks + +bool SerialFlashChip::begin(uint8_t pin) +{ + uint8_t id[5]; + uint8_t f; + uint32_t size; + + cspin_basereg = PIN_TO_BASEREG(pin); + cspin_bitmask = PIN_TO_BITMASK(pin); + SPIPORT.begin(); + pinMode(pin, OUTPUT); + CSRELEASE(); + readID(id); + f = 0; + size = capacity(id); + if (size > 16777216) { + // more than 16 Mbyte requires 32 bit addresses + f |= FLAG_32BIT_ADDR; + SPIPORT.beginTransaction(SPICONFIG); + if (id[0] == ID0_SPANSION) { + // spansion uses MSB of bank register + CSASSERT(); + SPIPORT.transfer16(0x1780); // bank register write + CSRELEASE(); + } else { + // micron & winbond & macronix use command + CSASSERT(); + SPIPORT.transfer(0x06); // write enable + CSRELEASE(); + delayMicroseconds(1); + CSASSERT(); + SPIPORT.transfer(0xB7); // enter 4 byte addr mode + CSRELEASE(); + } + SPIPORT.endTransaction(); + if (id[0] == ID0_MICRON) f |= FLAG_MULTI_DIE; + } + if (id[0] == ID0_SPANSION) { + // Spansion has separate suspend commands + f |= FLAG_DIFF_SUSPEND; + if (!id[4]) { + // Spansion chips with id[4] == 0 use 256K sectors + f |= FLAG_256K_BLOCKS; + } + } + if (id[0] == ID0_MICRON) { + // Micron requires busy checks with a different command + f |= FLAG_STATUS_CMD70; // TODO: all or just multi-die chips? + } + flags = f; + readID(id); + return true; +} + +// chips tested: https://github.com/PaulStoffregen/SerialFlash/pull/12#issuecomment-169596992 +// +void SerialFlashChip::sleep() +{ + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0xB9); // Deep power down command + CSRELEASE(); +} + +void SerialFlashChip::wakeup() +{ + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0xAB); // Wake up from deep power down command + CSRELEASE(); +} + +void SerialFlashChip::readID(uint8_t *buf) +{ + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0x9F); + buf[0] = SPIPORT.transfer(0); // manufacturer ID + buf[1] = SPIPORT.transfer(0); // memory type + buf[2] = SPIPORT.transfer(0); // capacity + if (buf[0] == ID0_SPANSION) { + buf[3] = SPIPORT.transfer(0); // ID-CFI + buf[4] = SPIPORT.transfer(0); // sector size + } + CSRELEASE(); + SPIPORT.endTransaction(); + //Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); +} + +void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes +{ + if (busy) wait(); + SPIPORT.beginTransaction(SPICONFIG); + CSASSERT(); + SPIPORT.transfer(0x4B); + SPIPORT.transfer16(0); + SPIPORT.transfer16(0); + for (int i=0; i<8; i++) { + buf[i] = SPIPORT.transfer(0); + } + CSRELEASE(); + SPIPORT.endTransaction(); +// Serial.printf("Serial Number: %02X %02X %02X %02X %02X %02X %02X %02X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); +} + +uint32_t SerialFlashChip::capacity(const uint8_t *id) +{ + uint32_t n = 1048576; // unknown chips, default to 1 MByte + + if (id[2] >= 16 && id[2] <= 31) { + n = 1ul << id[2]; + } else + if (id[2] >= 32 && id[2] <= 37) { + n = 1ul << (id[2] - 6); + } else + if ((id[0]==0 && id[1]==0 && id[2]==0) || + (id[0]==255 && id[1]==255 && id[2]==255)) { + n = 0; + } + //Serial.printf("capacity %lu\n", n); + return n; +} + +uint32_t SerialFlashChip::blockSize() +{ + // Spansion chips >= 512 mbit use 256K sectors + if (flags & FLAG_256K_BLOCKS) return 262144; + // everything else seems to have 64K sectors + return 65536; +} + + + + +/* +Chip Uniform Sector Erase + 20/21 52 D8/DC + ----- -- ----- +W25Q64CV 4 32 64 +W25Q128FV 4 32 64 +S25FL127S 64 +N25Q512A 4 64 +N25Q00AA 4 64 +S25FL512S 256 +SST26VF032 4 +*/ + + + +// size sector busy pgm/erase chip +// Part Mbyte kbyte ID bytes cmd suspend erase +// ---- ---- ----- -------- --- ------- ----- +// Winbond W25Q64CV 8 64 EF 40 17 +// Winbond W25Q128FV 16 64 EF 40 18 05 single 60 & C7 +// Winbond W25Q256FV 32 64 EF 40 19 +// Spansion S25FL064A 8 ? 01 02 16 +// Spansion S25FL127S 16 64 01 20 18 05 +// Spansion S25FL128P 16 64 01 20 18 +// Spansion S25FL256S 32 64 01 02 19 05 60 & C7 +// Spansion S25FL512S 64 256 01 02 20 +// Macronix MX25L12805D 16 ? C2 20 18 +// Macronix MX66L51235F 64 C2 20 1A +// Numonyx M25P128 16 ? 20 20 18 +// Micron M25P80 1 ? 20 20 14 +// Micron N25Q128A 16 64 20 BA 18 +// Micron N25Q512A 64 ? 20 BA 20 70 single C4 x2 +// Micron N25Q00AA 128 64 20 BA 21 single C4 x4 +// Micron MT25QL02GC 256 64 20 BA 22 70 C4 x2 +// SST SST25WF010 1/8 ? BF 25 02 +// SST SST25WF020 1/4 ? BF 25 03 +// SST SST25WF040 1/2 ? BF 25 04 +// SST SST25VF016B 1 ? BF 25 41 +// SST26VF016 ? BF 26 01 +// SST26VF032 ? BF 26 02 +// SST25VF032 4 64 BF 25 4A +// SST26VF064 8 ? BF 26 43 +// LE25U40CMC 1/2 64 62 06 13 + +SerialFlashChip SerialFlash; diff --git a/libraries/SerialFlash/SerialFlashDirectory.cpp b/libraries/SerialFlash/SerialFlashDirectory.cpp new file mode 100644 index 00000000..036a3c34 --- /dev/null +++ b/libraries/SerialFlash/SerialFlashDirectory.cpp @@ -0,0 +1,393 @@ +/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory + * https://github.com/PaulStoffregen/SerialFlash + * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com + * + * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. + * Please support PJRC's efforts to develop open source software by purchasing + * Teensy or other genuine PJRC products. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "SerialFlash.h" + +/* On-chip SerialFlash file allocation data structures: + + uint32_t signature = 0xFA96554C; + uint16_t maxfiles + uint16_t stringssize // div by 4 + uint16_t hashes[maxfiles] + struct { + uint32_t file_begin + uint32_t file_length + uint16_t string_index // div4 + } fileinfo[maxfiles] + char strings[stringssize] + +A 32 bit signature is stored at the beginning of the flash memory. +If 0xFFFFFFFF is seen, the entire chip should be assumed blank. +If any value other than 0xFA96554C is found, a different data format +is stored. This could should refuse to access the flash. + +The next 4 bytes store number of files and size of the strings +section, which allow the position of every other item to be found. +The string section size is the 16 bit integer times 4, which allows +up to 262140 bytes for string data. + +An array of 16 bit filename hashes allows for quick linear search +for potentially matching filenames. A hash value of 0xFFFF indicates +no file is allocated for the remainder of the array. + +Following the hashes, and array of 10 byte structs give the location +and length of the file's actual data, and the offset of its filename +in the strings section. + +Strings are null terminated. The remainder of the chip is file data. +*/ + +#define DEFAULT_MAXFILES 600 +#define DEFAULT_STRINGS_SIZE 25560 + + +static uint32_t check_signature(void) +{ + uint32_t sig[2]; + + SerialFlash.read(0, sig, 8); + //Serial.printf("sig: %08X %08X\n", sig[0], sig[1]); + if (sig[0] == 0xFA96554C) return sig[1]; + if (sig[0] == 0xFFFFFFFF) { + sig[0] = 0xFA96554C; + sig[1] = ((uint32_t)(DEFAULT_STRINGS_SIZE/4) << 16) | DEFAULT_MAXFILES; + SerialFlash.write(0, sig, 8); + while (!SerialFlash.ready()) ; // TODO: timeout + SerialFlash.read(0, sig, 8); + if (sig[0] == 0xFA96554C) return sig[1]; + } + return 0; +} + +static uint16_t filename_hash(const char *filename) +{ + // http://isthe.com/chongo/tech/comp/fnv/ + uint32_t hash = 2166136261; + const char *p; + + for (p=filename; *p; p++) { + hash ^= *p; + hash *= 16777619; + } + hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF + return hash; +} + +static bool filename_compare(const char *filename, uint32_t straddr) +{ + unsigned int i; + const char *p; + char buf[16]; + + p = filename; + while (1) { + SerialFlash.read(straddr, buf, sizeof(buf)); + straddr += sizeof(buf); + for (i=0; i < sizeof(buf); i++) { + if (*p++ != buf[i]) return false; + if (buf[i] == 0) return true; + } + } +} + +#if 0 +void pbuf(const void *buf, uint32_t len) +{ + const uint8_t *p = (const uint8_t *)buf; + do { + Serial.printf("%02X ", *p++); + } while (--len > 0); + Serial.println(); +} +#endif + +SerialFlashFile SerialFlashChip::open(const char *filename) +{ + uint32_t maxfiles, straddr; + uint16_t hash, hashtable[8]; + uint32_t i, n, index=0; + uint32_t buf[3]; + SerialFlashFile file; + + maxfiles = check_signature(); + //Serial.printf("sig: %08X\n", maxfiles); + if (!maxfiles) return file; + maxfiles &= 0xFFFF; + hash = filename_hash(filename); + //Serial.printf("hash %04X for \"%s\"\n", hash, filename); + while (index < maxfiles) { + n = 8; + if (n > maxfiles - index) n = maxfiles - index; + SerialFlash.read(8 + index * 2, hashtable, n * 2); + //Serial.printf(" read %u: ", 8 + index * 2); + //pbuf(hashtable, n * 2); + for (i=0; i < n; i++) { + if (hashtable[i] == hash) { + //Serial.printf(" hash match at index %u\n", index+i); + buf[2] = 0; + SerialFlash.read(8 + maxfiles * 2 + (index+i) * 10, buf, 10); + + //Serial.printf(" maxf=%d, index=%d, i=%d\n", maxfiles, index, i); + //Serial.printf(" read %u: ", 8 + maxfiles * 2 + (index+i) * 10); + //pbuf(buf, 10); + straddr = 8 + maxfiles * 12 + buf[2] * 4; + //Serial.printf(" straddr = %u\n", straddr); + if (filename_compare(filename, straddr)) { + //Serial.printf(" match!\n"); + //Serial.printf(" addr = %u\n", buf[0]); + //Serial.printf(" len = %u\n", buf[1]); + file.address = buf[0]; + file.length = buf[1]; + file.offset = 0; + file.dirindex = index + i; + return file; + } + } else if (hashtable[i] == 0xFFFF) { + return file; + } + } + index += n; + } + return file; +} + +bool SerialFlashChip::exists(const char *filename) +{ + SerialFlashFile file = open(filename); + return (bool)file; +} + +bool SerialFlashChip::remove(const char *filename) +{ + SerialFlashFile file = open(filename); + return remove(file); +} + +bool SerialFlashChip::remove(SerialFlashFile &file) +{ + // To "remove" a file, we simply zero its hash in the lookup + // table, so it can't be found by open(). The space on the + // flash memory is not freed. + if (!file) return false; + uint16_t hash; + SerialFlash.read(8 + file.dirindex * 2, &hash, 2); + //Serial.printf("remove hash %04X at %d index\n", hash, file.dirindex); + hash ^= 0xFFFF; // write zeros to all ones + SerialFlash.write(8 + file.dirindex * 2, &hash, 2); + while (!SerialFlash.ready()) ; // wait... TODO: timeout + SerialFlash.read(8 + file.dirindex * 2, &hash, 2); + if (hash != 0) { + //Serial.printf("remove failed, hash %04X\n", hash); + return false; + } + file.address = 0; + file.length = 0; + return true; +} + +static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) +{ + uint16_t hashtable[8]; + uint32_t i, n, index=0; + + do { + n = 8; + if (index + n > maxfiles) n = maxfiles - index; + SerialFlash.read(8 + index * 2, hashtable, n * 2); + for (i=0; i < n; i++) { + if (hashtable[i] == 0xFFFF) return index + i; + } + index += n; + } while (index < maxfiles); + return 0xFFFFFFFF; +} + +static uint32_t string_length(uint32_t addr) +{ + char buf[16]; + const char *p; + uint32_t len=0; + + while (1) { + SerialFlash.read(addr, buf, sizeof(buf)); + for (p=buf; p < buf + sizeof(buf); p++) { + len++; + if (*p == 0) return len; + } + addr += sizeof(buf); + } +} + +// uint32_t signature = 0xFA96554C; +// uint16_t maxfiles +// uint16_t stringssize // div by 4 +// uint16_t hashes[maxfiles] +// struct { +// uint32_t file_begin +// uint32_t file_length +// uint16_t string_index // div 4 +// } fileinfo[maxfiles] +// char strings[stringssize] + +bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t align) +{ + uint32_t maxfiles, stringsize; + uint32_t index, buf[3]; + uint32_t address, straddr, len; + SerialFlashFile file; + + // check if the file already exists + if (exists(filename)) return false; + + // first, get the filesystem parameters + maxfiles = check_signature(); + if (!maxfiles) return false; + stringsize = (maxfiles & 0xFFFF0000) >> 14; + maxfiles &= 0xFFFF; + + // find the first unused slot for this file + index = find_first_unallocated_file_index(maxfiles); + if (index >= maxfiles) return false; + //Serial.printf("index = %u\n", index); + // compute where to store the filename and actual data + straddr = 8 + maxfiles * 12; + if (index == 0) { + address = straddr + stringsize; + } else { + buf[2] = 0; + SerialFlash.read(8 + maxfiles * 2 + (index-1) * 10, buf, 10); + address = buf[0] + buf[1]; + straddr += buf[2] * 4; + straddr += string_length(straddr); + straddr = (straddr + 3) & 0x0003FFFC; + } + //Serial.printf("straddr = %u\n", straddr); + //Serial.printf("address = %u\n", address); + //Serial.printf("length = %u\n", length); + if (align > 0) { + // for files aligned to sectors, adjust addr & len + address += align - 1; + address /= align; + address *= align; + //Serial.printf("align address = %u\n", address); + length += align - 1; + length /= align; + length *= align; + //Serial.printf("align length = %u\n", length); + } else { + // always align every file to a page boundary + // for predictable write latency and to guarantee + // write suspend for reading another file can't + // conflict on the same page (2 files never share + // a write page). + address = (address + 255) & 0xFFFFFF00; + } + //Serial.printf("address = %u\n", address); + // last check, if enough space exists... + len = strlen(filename); + // TODO: check for enough string space for filename + uint8_t id[3]; + SerialFlash.readID(id); + if (address + length > SerialFlash.capacity(id)) return false; + + SerialFlash.write(straddr, filename, len+1); + buf[0] = address; + buf[1] = length; + buf[2] = (straddr - (8 + maxfiles * 12)) / 4; + SerialFlash.write(8 + maxfiles * 2 + index * 10, buf, 10); + //Serial.printf(" write %u: ", 8 + maxfiles * 2 + index * 10); + //pbuf(buf, 10); + while (!SerialFlash.ready()) ; // TODO: timeout + + buf[0] = filename_hash(filename); + //Serial.printf("hash = %04X\n", buf[0]); + SerialFlash.write(8 + index * 2, buf, 2); + while (!SerialFlash.ready()) ; // TODO: timeout + return true; +} + +bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize) +{ + uint32_t maxfiles, index, straddr; + uint32_t i, n; + uint32_t buf[2]; + uint16_t hash; + char str[16], *p=filename; + + filename[0] = 0; + maxfiles = check_signature(); + if (!maxfiles) return false; + maxfiles &= 0xFFFF; + index = dirindex; + while (1) { + if (index >= maxfiles) return false; + //Serial.printf("readdir, index = %u\n", index); + SerialFlash.read(8 + index * 2, &hash, 2); + if (hash != 0) break; + index++; // skip deleted entries + } + dirindex = index + 1; + buf[1] = 0; + SerialFlash.read(8 + 4 + maxfiles * 2 + index * 10, buf, 6); + if (buf[0] == 0xFFFFFFFF) return false; + filesize = buf[0]; + straddr = 8 + maxfiles * 12 + buf[1] * 4; + //Serial.printf(" length = %u\n", buf[0]); + //Serial.printf(" straddr = %u\n", straddr); + + while (strsize) { + n = strsize; + if (n > sizeof(str)) n = sizeof(str); + SerialFlash.read(straddr, str, n); + for (i=0; i < n; i++) { + *p++ = str[i]; + if (str[i] == 0) { + //Serial.printf(" name = %s\n", filename); + return true; + } + } + strsize -= n; + straddr += n; + } + *(p - 1) = 0; + //Serial.printf(" name(overflow) = %s\n", filename); + return true; +} + + +void SerialFlashFile::erase() +{ + uint32_t i, blocksize; + + blocksize = SerialFlash.blockSize(); + if (address & (blocksize - 1)) return; // must begin on a block boundary + if (length & (blocksize - 1)) return; // must be exact number of blocks + for (i=0; i < length; i += blocksize) { + SerialFlash.eraseBlock(address + i); + } +} + diff --git a/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino b/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino new file mode 100644 index 00000000..ff91b828 --- /dev/null +++ b/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino @@ -0,0 +1,133 @@ +// SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + +#include +#include +#include + +const int SDchipSelect = 4; // Audio Shield has SD card CS on pin 10 +const int FlashChipSelect = 21; // digital pin for flash chip CS pin + +void setup() { + //uncomment these if using Teensy audio shield + //SPI.setSCK(14); // Audio shield has SCK on pin 14 + //SPI.setMOSI(7); // Audio shield has MOSI on pin 7 + + //uncomment these if you have other SPI chips connected + //to keep them disabled while using only SerialFlash + //pinMode(4, INPUT_PULLUP); + //pinMode(10, INPUT_PULLUP); + + Serial.begin(9600); + + // wait up to 10 seconds for Arduino Serial Monitor + unsigned long startMillis = millis(); + while (!Serial && (millis() - startMillis < 10000)) ; + delay(100); + Serial.println("Copy all files from SD Card to SPI Flash"); + + if (!SD.begin(SDchipSelect)) { + error("Unable to access SD card"); + } + if (!SerialFlash.begin(FlashChipSelect)) { + error("Unable to access SPI Flash chip"); + } + + int count = 0; + File rootdir = SD.open("/"); + while (1) { + // open a file from the SD card + Serial.println(); + File f = rootdir.openNextFile(); + if (!f) break; + const char *filename = f.name(); + Serial.print(filename); + Serial.print(" "); + unsigned long length = f.size(); + Serial.println(length); + + // check if this file is already on the Flash chip + if (SerialFlash.exists(filename)) { + Serial.println(" already exists on the Flash chip"); + SerialFlashFile ff = SerialFlash.open(filename); + if (ff && ff.size() == f.size()) { + Serial.println(" size is the same, comparing data..."); + if (compareFiles(f, ff) == true) { + Serial.println(" files are identical :)"); + f.close(); + ff.close(); + continue; // advance to next file + } else { + Serial.println(" files are different"); + } + } else { + Serial.print(" size is different, "); + Serial.print(ff.size()); + Serial.println(" bytes"); + } + // delete the copy on the Flash chip, if different + Serial.println(" delete file from Flash chip"); + SerialFlash.remove(filename); + } + + // create the file on the Flash chip and copy data + if (SerialFlash.create(filename, length)) { + SerialFlashFile ff = SerialFlash.open(filename); + if (ff) { + Serial.print(" copying"); + // copy data loop + unsigned long count = 0; + unsigned char dotcount = 9; + while (count < length) { + char buf[256]; + unsigned int n; + n = f.read(buf, 256); + ff.write(buf, n); + count = count + n; + Serial.print("."); + if (++dotcount > 100) { + Serial.println(); + dotcount = 0; + } + } + ff.close(); + if (dotcount > 0) Serial.println(); + } else { + Serial.println(" error opening freshly created file!"); + } + } else { + Serial.println(" unable to create file"); + } + f.close(); + } + rootdir.close(); + delay(10); + Serial.println("Finished All Files"); +} + + +bool compareFiles(File &file, SerialFlashFile &ffile) { + file.seek(0); + ffile.seek(0); + unsigned long count = file.size(); + while (count > 0) { + char buf1[128], buf2[128]; + unsigned long n = count; + if (n > 128) n = 128; + file.read(buf1, n); + ffile.read(buf2, n); + if (memcmp(buf1, buf2, n) != 0) return false; // differ + count = count - n; + } + return true; // all data identical +} + + +void loop() { +} + +void error(const char *message) { + while (1) { + Serial.println(message); + delay(2500); + } +} diff --git a/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino b/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino new file mode 100644 index 00000000..703ac142 --- /dev/null +++ b/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino @@ -0,0 +1,275 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + * ------------------------------------------------------------------------- + * + * This is example code to 1) format an SPI Flash chip, and 2) copy raw + * audio files (mono channel, 16 bit signed, 44100Hz) to it using the + * SerialFlash library. The audio can then be played back using the + * AudioPlaySerialflashRaw object in the Teensy Audio library. + * + * To convert a .wav file to the proper .RAW format, use sox: + * sox input.wav -r 44100 -b 16 --norm -e signed-integer -t raw OUTPUT.RAW remix 1,2 + * + * Note that the OUTPUT.RAW filename must be all caps and contain only the following + * characters: A-Z, 0-9, comma, period, colon, dash, underscore. (The SerialFlash + * library converts filenames to caps, so to avoid confusion we just enforce it here). + * + * It is a little difficult to see what is happening; aswe are using the Serial port + * to upload files, we can't just throw out debug information. Instead, we use the LED + * (pin 13) to convey state. + * + * While the chip is being formatted, the LED (pin 13) will toggle at 1Hz rate. When + * the formatting is done, it flashes quickly (10Hz) for one second, then stays on + * solid. When nothing has been received for 3 seconds, the upload is assumed to be + * completed, and the light goes off. + * + * Use the 'rawfile-uploader.py' python script (included in the extras folder) to upload + * the files. You can start the script as soon as the Teensy is turned on, and the + * USB serial upload will just buffer and wait until the flash is formatted. + * + * This code was written by Wyatt Olson (originally as part + * of Drum Master http://drummaster.digitalcave.ca and later modified into a + * standalone sample). + * + * Enjoy! + * + * SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + */ + +#include +#include + +//Buffer sizes +#define USB_BUFFER_SIZE 128 +#define FLASH_BUFFER_SIZE 4096 + +//Max filename length (8.3 plus a null char terminator) +#define FILENAME_STRING_SIZE 13 + +//State machine +#define STATE_START 0 +#define STATE_SIZE 1 +#define STATE_CONTENT 2 + +//Special bytes in the communication protocol +#define BYTE_START 0x7e +#define BYTE_ESCAPE 0x7d +#define BYTE_SEPARATOR 0x7c + + +//SPI Pins (these are the values on the Audio board; change them if you have different ones) +#define MOSI 7 +#define MISO 12 +#define SCK 14 +#define CSPIN 21 + +void setup(){ + Serial.begin(9600); //Teensy serial is always at full USB speed and buffered... the baud rate here is required but ignored + + pinMode(13, OUTPUT); + + //Set up SPI + SPI.setMOSI(MOSI); + SPI.setMISO(MISO); + SPI.setSCK(SCK); + SerialFlash.begin(CSPIN); + + //We start by formatting the flash... + uint8_t id[5]; + SerialFlash.readID(id); + SerialFlash.eraseAll(); + + //Flash LED at 1Hz while formatting + while (!SerialFlash.ready()) { + delay(500); + digitalWrite(13, HIGH); + delay(500); + digitalWrite(13, LOW); + } + + //Quickly flash LED a few times when completed, then leave the light on solid + for(uint8_t i = 0; i < 10; i++){ + delay(100); + digitalWrite(13, HIGH); + delay(100); + digitalWrite(13, LOW); + } + digitalWrite(13, HIGH); + + //We are now going to wait for the upload program + while(!Serial.available()); + + SerialFlashFile flashFile; + + uint8_t state = STATE_START; + uint8_t escape = 0; + uint8_t fileSizeIndex = 0; + uint32_t fileSize = 0; + char filename[FILENAME_STRING_SIZE]; + + char usbBuffer[USB_BUFFER_SIZE]; + uint8_t flashBuffer[FLASH_BUFFER_SIZE]; + + uint16_t flashBufferIndex = 0; + uint8_t filenameIndex = 0; + + uint32_t lastReceiveTime = millis(); + + //We assume the serial receive part is finished when we have not received something for 3 seconds + while(Serial.available() || lastReceiveTime + 3000 > millis()){ + uint16_t available = Serial.readBytes(usbBuffer, USB_BUFFER_SIZE); + if (available){ + lastReceiveTime = millis(); + } + + for (uint16_t usbBufferIndex = 0; usbBufferIndex < available; usbBufferIndex++){ + uint8_t b = usbBuffer[usbBufferIndex]; + + if (state == STATE_START){ + //Start byte. Repeat start is fine. + if (b == BYTE_START){ + for (uint8_t i = 0; i < FILENAME_STRING_SIZE; i++){ + filename[i] = 0x00; + } + filenameIndex = 0; + } + //Valid characters are A-Z, 0-9, comma, period, colon, dash, underscore + else if ((b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '.' || b == ',' || b == ':' || b == '-' || b == '_'){ + filename[filenameIndex++] = b; + if (filenameIndex >= FILENAME_STRING_SIZE){ + //Error name too long + flushError(); + return; + } + } + //Filename end character + else if (b == BYTE_SEPARATOR){ + if (filenameIndex == 0){ + //Error empty filename + flushError(); + return; + } + + //Change state + state = STATE_SIZE; + fileSizeIndex = 0; + fileSize = 0; + + } + //Invalid character + else { + //Error bad filename + flushError(); + return; + } + } + //We read 4 bytes as a uint32_t for file size + else if (state == STATE_SIZE){ + if (fileSizeIndex < 4){ + fileSize = (fileSize << 8) + b; + fileSizeIndex++; + } + else if (b == BYTE_SEPARATOR){ + state = STATE_CONTENT; + flashBufferIndex = 0; + escape = 0; + + if (SerialFlash.exists(filename)){ + SerialFlash.remove(filename); //It doesn't reclaim the space, but it does let you create a new file with the same name. + } + + //Create a new file and open it for writing + if (SerialFlash.create(filename, fileSize)) { + flashFile = SerialFlash.open(filename); + if (!flashFile) { + //Error flash file open + flushError(); + return; + } + } + else { + //Error flash create (no room left?) + flushError(); + return; + } + } + else { + //Error invalid length requested + flushError(); + return; + } + } + else if (state == STATE_CONTENT){ + //Previous byte was escaped; unescape and add to buffer + if (escape){ + escape = 0; + flashBuffer[flashBufferIndex++] = b ^ 0x20; + } + //Escape the next byte + else if (b == BYTE_ESCAPE){ + //Serial.println("esc"); + escape = 1; + } + //End of file + else if (b == BYTE_START){ + //Serial.println("End of file"); + state = STATE_START; + flashFile.write(flashBuffer, flashBufferIndex); + flashFile.close(); + flashBufferIndex = 0; + } + //Normal byte; add to buffer + else { + flashBuffer[flashBufferIndex++] = b; + } + + //The buffer is filled; write to SD card + if (flashBufferIndex >= FLASH_BUFFER_SIZE){ + flashFile.write(flashBuffer, FLASH_BUFFER_SIZE); + flashBufferIndex = 0; + } + } + } + } + + //Success! Turn the light off. + digitalWrite(13, LOW); +} + +void loop(){ + //Do nothing. +} + +void flushError(){ + uint32_t lastReceiveTime = millis(); + char usbBuffer[USB_BUFFER_SIZE]; + //We assume the serial receive part is finished when we have not received something for 3 seconds + while(Serial.available() || lastReceiveTime + 3000 > millis()){ + if (Serial.readBytes(usbBuffer, USB_BUFFER_SIZE)){ + lastReceiveTime = millis(); + } + } +} diff --git a/libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino b/libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino new file mode 100644 index 00000000..d3b3f4d7 --- /dev/null +++ b/libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino @@ -0,0 +1,80 @@ +//SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + +#include +#include + +const int FlashChipSelect = 21; // digital pin for flash chip CS pin + +SerialFlashFile file; + +const unsigned long testIncrement = 4096; + +void setup() { + //uncomment these if using Teensy audio shield + //SPI.setSCK(14); // Audio shield has SCK on pin 14 + //SPI.setMOSI(7); // Audio shield has MOSI on pin 7 + + //uncomment these if you have other SPI chips connected + //to keep them disabled while using only SerialFlash + //pinMode(4, INPUT_PULLUP); + //pinMode(10, INPUT_PULLUP); + + Serial.begin(9600); + + // wait up to 10 seconds for Arduino Serial Monitor + unsigned long startMillis = millis(); + while (!Serial && (millis() - startMillis < 10000)) ; + delay(100); + + SerialFlash.begin(FlashChipSelect); + unsigned char id[5]; + SerialFlash.readID(id); + unsigned long size = SerialFlash.capacity(id); + + if (size > 0) { + Serial.print("Flash Memory has "); + Serial.print(size); + Serial.println(" bytes."); + Serial.println("Erasing ALL Flash Memory:"); + // Estimate the (lengthy) wait time. + Serial.print(" estimated wait: "); + int seconds = (float)size / eraseBytesPerSecond(id) + 0.5; + Serial.print(seconds); + Serial.println(" seconds."); + Serial.println(" Yes, full chip erase is SLOW!"); + SerialFlash.eraseAll(); + unsigned long dotMillis = millis(); + unsigned char dotcount = 0; + while (SerialFlash.ready() == false) { + if (millis() - dotMillis > 1000) { + dotMillis = dotMillis + 1000; + Serial.print("."); + dotcount = dotcount + 1; + if (dotcount >= 60) { + Serial.println(); + dotcount = 0; + } + } + } + if (dotcount > 0) Serial.println(); + Serial.println("Erase completed"); + unsigned long elapsed = millis() - startMillis; + Serial.print(" actual wait: "); + Serial.print(elapsed / 1000ul); + Serial.println(" seconds."); + } +} + +float eraseBytesPerSecond(const unsigned char *id) { + if (id[0] == 0x20) return 152000.0; // Micron + if (id[0] == 0x01) return 500000.0; // Spansion + if (id[0] == 0xEF) return 419430.0; // Winbond + if (id[0] == 0xC2) return 279620.0; // Macronix + return 320000.0; // guess? +} + + +void loop() { + +} + diff --git a/libraries/SerialFlash/examples/FileWrite/FileWrite.ino b/libraries/SerialFlash/examples/FileWrite/FileWrite.ino new file mode 100755 index 00000000..dbeb438a --- /dev/null +++ b/libraries/SerialFlash/examples/FileWrite/FileWrite.ino @@ -0,0 +1,50 @@ +//SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + +#include +#include + +#define FSIZE 256 + +const char *filename = "myfile.txt"; +const char *contents = "0123456789ABCDEF"; + +const int FlashChipSelect = 21; // digital pin for flash chip CS pin + +void setup() { + Serial.begin(9600); + + // wait for Arduino Serial Monitor + while (!Serial) ; + delay(100); + + // Init. SPI Flash chip + if (!SerialFlash.begin(FlashChipSelect)) { + Serial.println("Unable to access SPI Flash chip"); + } + + SerialFlashFile file; + + // Create the file if it doesn't exist + if (!create_if_not_exists(filename)) { + Serial.println("Not enough space to create file " + String(filename)); + return; + } + + // Open the file and write test data + file = SerialFlash.open(filename); + file.write(contents, strlen(contents) + 1); + Serial.println("String \"" + String(contents) + "\" written to file " + String(filename)); +} + +bool create_if_not_exists (const char *filename) { + if (!SerialFlash.exists(filename)) { + Serial.println("Creating file " + String(filename)); + return SerialFlash.create(filename, FSIZE); + } + + Serial.println("File " + String(filename) + " already exists"); + return true; +} + +void loop() { +} diff --git a/libraries/SerialFlash/examples/ListFiles/ListFiles.ino b/libraries/SerialFlash/examples/ListFiles/ListFiles.ino new file mode 100644 index 00000000..bc15b89b --- /dev/null +++ b/libraries/SerialFlash/examples/ListFiles/ListFiles.ino @@ -0,0 +1,63 @@ +// SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + +#include +#include + +const int FlashChipSelect = 21; // digital pin for flash chip CS pin + +void setup() { + //uncomment these if using Teensy audio shield + //SPI.setSCK(14); // Audio shield has SCK on pin 14 + //SPI.setMOSI(7); // Audio shield has MOSI on pin 7 + + //uncomment these if you have other SPI chips connected + //to keep them disabled while using only SerialFlash + //pinMode(4, INPUT_PULLUP); + //pinMode(10, INPUT_PULLUP); + + Serial.begin(9600); + + // wait for Arduino Serial Monitor + while (!Serial) ; + delay(100); + Serial.println("All Files on SPI Flash chip:"); + + if (!SerialFlash.begin(FlashChipSelect)) { + error("Unable to access SPI Flash chip"); + } + + SerialFlash.opendir(); + unsigned int count = 0; + while (1) { + char filename[64]; + unsigned long filesize; + + if (SerialFlash.readdir(filename, sizeof(filename), filesize)) { + Serial.print(" "); + Serial.print(filename); + spaces(20 - strlen(filename)); + Serial.print(" "); + Serial.print(filesize); + Serial.print(" bytes"); + Serial.println(); + } else { + break; // no more files + } + } +} + +void spaces(int num) { + for (int i=0; i < num; i++) { + Serial.print(" "); + } +} + +void loop() { +} + +void error(const char *message) { + while (1) { + Serial.println(message); + delay(2500); + } +} diff --git a/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino b/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino new file mode 100644 index 00000000..7cd47cb2 --- /dev/null +++ b/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino @@ -0,0 +1,501 @@ +// SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash +// +// RawHardwareTest - Check if a SPI Flash chip is compatible +// with SerialFlash by performing many read and write tests +// to its memory. +// +// The chip should be fully erased before running this test. +// Use the EraseEverything to do a (slow) full chip erase. +// +// Normally you should NOT access the flash memory directly, +// as this test program does. You should create files and +// read and write the files. File creation allocates space +// with program & erase boundaries within the chip, to allow +// reading from any other files while a file is busy writing +// or erasing (if created as erasable). +// +// If you discover an incompatible chip, please report it here: +// https://github.com/PaulStoffregen/SerialFlash/issues +// You MUST post the complete output of this program, and +// the exact part number and manufacturer of the chip. + + +#include +#include + +const int FlashChipSelect = 21; // digital pin for flash chip CS pin + +SerialFlashFile file; + +const unsigned long testIncrement = 4096; + +void setup() { + + //uncomment these if using Teensy audio shield + //SPI.setSCK(14); // Audio shield has SCK on pin 14 + //SPI.setMOSI(7); // Audio shield has MOSI on pin 7 + + //uncomment these if you have other SPI chips connected + //to keep them disabled while using only SerialFlash + //pinMode(4, INPUT_PULLUP); + //pinMode(10, INPUT_PULLUP); + + Serial.begin(9600); + + while (!Serial) ; + delay(100); + + Serial.println("Raw SerialFlash Hardware Test"); + SerialFlash.begin(FlashChipSelect); + + if (test()) { + Serial.println(); + Serial.println("All Tests Passed :-)"); + Serial.println(); + Serial.println("Test data was written to your chip. You must run"); + Serial.println("EraseEverything before using this chip for files."); + } else { + Serial.println(); + Serial.println("Tests Failed :{"); + Serial.println(); + Serial.println("The flash chip may be left in an improper state."); + Serial.println("You might need to power cycle to return to normal."); + } +} + + +bool test() { + unsigned char buf[256], sig[256], buf2[8]; + unsigned long address, count, chipsize, blocksize; + unsigned long usec; + bool first; + + // Read the chip identification + Serial.println(); + Serial.println("Read Chip Identification:"); + SerialFlash.readID(buf); + Serial.print(" JEDEC ID: "); + Serial.print(buf[0], HEX); + Serial.print(" "); + Serial.print(buf[1], HEX); + Serial.print(" "); + Serial.println(buf[2], HEX); + Serial.print(" Part Nummber: "); + Serial.println(id2chip(buf)); + Serial.print(" Memory Size: "); + chipsize = SerialFlash.capacity(buf); + Serial.print(chipsize); + Serial.println(" bytes"); + if (chipsize == 0) return false; + Serial.print(" Block Size: "); + blocksize = SerialFlash.blockSize(); + Serial.print(blocksize); + Serial.println(" bytes"); + + + // Read the entire chip. Every test location must be + // erased, or have a previously tested signature + Serial.println(); + Serial.println("Reading Chip..."); + memset(buf, 0, sizeof(buf)); + memset(sig, 0, sizeof(sig)); + memset(buf2, 0, sizeof(buf2)); + address = 0; + count = 0; + first = true; + while (address < chipsize) { + SerialFlash.read(address, buf, 8); + //Serial.print(" addr = "); + //Serial.print(address, HEX); + //Serial.print(", data = "); + //printbuf(buf, 8); + create_signature(address, sig); + if (is_erased(buf, 8) == false) { + if (equal_signatures(buf, sig) == false) { + Serial.print(" Previous data found at address "); + Serial.println(address); + Serial.println(" You must fully erase the chip before this test"); + Serial.print(" found this: "); + printbuf(buf, 8); + Serial.print(" correct: "); + printbuf(sig, 8); + return false; + } + } else { + count = count + 1; // number of blank signatures + } + if (first) { + address = address + (testIncrement - 8); + first = false; + } else { + address = address + 8; + first = true; + } + } + + + // Write any signatures that were blank on the original check + if (count > 0) { + Serial.println(); + Serial.print("Writing "); + Serial.print(count); + Serial.println(" signatures"); + memset(buf, 0, sizeof(buf)); + memset(sig, 0, sizeof(sig)); + memset(buf2, 0, sizeof(buf2)); + address = 0; + first = true; + while (address < chipsize) { + SerialFlash.read(address, buf, 8); + if (is_erased(buf, 8)) { + create_signature(address, sig); + //Serial.printf("write %08X: data: ", address); + //printbuf(sig, 8); + SerialFlash.write(address, sig, 8); + while (!SerialFlash.ready()) ; // wait + SerialFlash.read(address, buf, 8); + if (equal_signatures(buf, sig) == false) { + Serial.print(" error writing signature at "); + Serial.println(address); + Serial.print(" Read this: "); + printbuf(buf, 8); + Serial.print(" Expected: "); + printbuf(sig, 8); + return false; + } + } + if (first) { + address = address + (testIncrement - 8); + first = false; + } else { + address = address + 8; + first = true; + } + } + } else { + Serial.println(" all signatures present from prior tests"); + } + + + // Read all the signatures again, just to be sure + // checks prior writing didn't corrupt any other data + Serial.println(); + Serial.println("Double Checking All Signatures:"); + memset(buf, 0, sizeof(buf)); + memset(sig, 0, sizeof(sig)); + memset(buf2, 0, sizeof(buf2)); + count = 0; + address = 0; + first = true; + while (address < chipsize) { + SerialFlash.read(address, buf, 8); + create_signature(address, sig); + if (equal_signatures(buf, sig) == false) { + Serial.print(" error in signature at "); + Serial.println(address); + Serial.print(" Read this: "); + printbuf(buf, 8); + Serial.print(" Expected: "); + printbuf(sig, 8); + return false; + } + count = count + 1; + if (first) { + address = address + (testIncrement - 8); + first = false; + } else { + address = address + 8; + first = true; + } + } + Serial.print(" all "); + Serial.print(count); + Serial.println(" signatures read ok"); + + + // Read pairs of adjacent signatures + // check read works across boundaries + Serial.println(); + Serial.println("Checking Signature Pairs"); + memset(buf, 0, sizeof(buf)); + memset(sig, 0, sizeof(sig)); + memset(buf2, 0, sizeof(buf2)); + count = 0; + address = testIncrement - 8; + first = true; + while (address < chipsize - 8) { + SerialFlash.read(address, buf, 16); + create_signature(address, sig); + create_signature(address + 8, sig + 8); + if (memcmp(buf, sig, 16) != 0) { + Serial.print(" error in signature pair at "); + Serial.println(address); + Serial.print(" Read this: "); + printbuf(buf, 16); + Serial.print(" Expected: "); + printbuf(sig, 16); + return false; + } + count = count + 1; + address = address + testIncrement; + } + Serial.print(" all "); + Serial.print(count); + Serial.println(" signature pairs read ok"); + + + // Write data and read while write in progress + Serial.println(); + Serial.println("Checking Read-While-Write (Program Suspend)"); + address = 256; + while (address < chipsize) { // find a blank space + SerialFlash.read(address, buf, 256); + if (is_erased(buf, 256)) break; + address = address + 256; + } + if (address >= chipsize) { + Serial.println(" error, unable to find any blank space!"); + return false; + } + for (int i=0; i < 256; i += 8) { + create_signature(address + i, sig + i); + } + Serial.print(" write 256 bytes at "); + Serial.println(address); + Serial.flush(); + SerialFlash.write(address, sig, 256); + usec = micros(); + if (SerialFlash.ready()) { + Serial.println(" error, chip did not become busy after write"); + return false; + } + SerialFlash.read(0, buf2, 8); // read while busy writing + while (!SerialFlash.ready()) ; // wait + usec = micros() - usec; + Serial.print(" write time was "); + Serial.print(usec); + Serial.println(" microseconds."); + SerialFlash.read(address, buf, 256); + if (memcmp(buf, sig, 256) != 0) { + Serial.println(" error writing to flash"); + Serial.print(" Read this: "); + printbuf(buf, 256); + Serial.print(" Expected: "); + printbuf(sig, 256); + return false; + } + create_signature(0, sig); + if (memcmp(buf2, sig, 8) != 0) { + Serial.println(" error, incorrect read while writing"); + Serial.print(" Read this: "); + printbuf(buf2, 256); + Serial.print(" Expected: "); + printbuf(sig, 256); + return false; + } + Serial.print(" read-while-writing: "); + printbuf(buf2, 8); + Serial.println(" test passed, good read while writing"); + + + + // Erase a block and read while erase in progress + if (chipsize >= 262144 + blocksize + testIncrement) { + Serial.println(); + Serial.println("Checking Read-While-Erase (Erase Suspend)"); + memset(buf, 0, sizeof(buf)); + memset(sig, 0, sizeof(sig)); + memset(buf2, 0, sizeof(buf2)); + SerialFlash.eraseBlock(262144); + usec = micros(); + delayMicroseconds(50); + if (SerialFlash.ready()) { + Serial.println(" error, chip did not become busy after erase"); + return false; + } + SerialFlash.read(0, buf2, 8); // read while busy writing + while (!SerialFlash.ready()) ; // wait + usec = micros() - usec; + Serial.print(" erase time was "); + Serial.print(usec); + Serial.println(" microseconds."); + // read all signatures, check ones in this block got + // erased, and all the others are still intact + address = 0; + first = true; + while (address < chipsize) { + SerialFlash.read(address, buf, 8); + if (address >= 262144 && address < 262144 + blocksize) { + if (is_erased(buf, 8) == false) { + Serial.print(" error in erasing at "); + Serial.println(address); + Serial.print(" Read this: "); + printbuf(buf, 8); + return false; + } + } else { + create_signature(address, sig); + if (equal_signatures(buf, sig) == false) { + Serial.print(" error in signature at "); + Serial.println(address); + Serial.print(" Read this: "); + printbuf(buf, 8); + Serial.print(" Expected: "); + printbuf(sig, 8); + return false; + } + } + if (first) { + address = address + (testIncrement - 8); + first = false; + } else { + address = address + 8; + first = true; + } + } + Serial.print(" erase correctly erased "); + Serial.print(blocksize); + Serial.println(" bytes"); + // now check if the data we read during erase is good + create_signature(0, sig); + if (memcmp(buf2, sig, 8) != 0) { + Serial.println(" error, incorrect read while erasing"); + Serial.print(" Read this: "); + printbuf(buf2, 256); + Serial.print(" Expected: "); + printbuf(sig, 256); + return false; + } + Serial.print(" read-while-erasing: "); + printbuf(buf2, 8); + Serial.println(" test passed, good read while erasing"); + + } else { + Serial.println("Skip Read-While-Erase, this chip is too small"); + } + + + + + return true; +} + + +void loop() { + // do nothing after the test +} + +const char * id2chip(const unsigned char *id) +{ + if (id[0] == 0xEF) { + // Winbond + if (id[1] == 0x40) { + if (id[2] == 0x14) return "W25Q80BV"; + if (id[2] == 0x17) return "W25Q64FV"; + if (id[2] == 0x18) return "W25Q128FV"; + if (id[2] == 0x19) return "W25Q256FV"; + } + } + if (id[0] == 0x01) { + // Spansion + if (id[1] == 0x02) { + if (id[2] == 0x16) return "S25FL064A"; + if (id[2] == 0x19) return "S25FL256S"; + if (id[2] == 0x20) return "S25FL512S"; + } + if (id[1] == 0x20) { + if (id[2] == 0x18) return "S25FL127S"; + } + } + if (id[0] == 0xC2) { + // Macronix + if (id[1] == 0x20) { + if (id[2] == 0x18) return "MX25L12805D"; + } + } + if (id[0] == 0x20) { + // Micron + if (id[1] == 0xBA) { + if (id[2] == 0x20) return "N25Q512A"; + if (id[2] == 0x21) return "N25Q00AA"; + } + if (id[1] == 0xBB) { + if (id[2] == 0x22) return "MT25QL02GC"; + } + } + if (id[0] == 0xBF) { + // SST + if (id[1] == 0x25) { + if (id[2] == 0x02) return "SST25WF010"; + if (id[2] == 0x03) return "SST25WF020"; + if (id[2] == 0x04) return "SST25WF040"; + if (id[2] == 0x41) return "SST25VF016B"; + if (id[2] == 0x4A) return "SST25VF032"; + } + if (id[1] == 0x25) { + if (id[2] == 0x01) return "SST26VF016"; + if (id[2] == 0x02) return "SST26VF032"; + if (id[2] == 0x43) return "SST26VF064"; + } + } + return "(unknown chip)"; +} + +void print_signature(const unsigned char *data) +{ + Serial.print("data="); + for (unsigned char i=0; i < 8; i++) { + Serial.print(data[i]); + Serial.print(" "); + } + Serial.println(); +} + +void create_signature(unsigned long address, unsigned char *data) +{ + data[0] = address >> 24; + data[1] = address >> 16; + data[2] = address >> 8; + data[3] = address; + unsigned long hash = 2166136261ul; + for (unsigned char i=0; i < 4; i++) { + hash ^= data[i]; + hash *= 16777619ul; + } + data[4] = hash; + data[5] = hash >> 8; + data[6] = hash >> 16; + data[7] = hash >> 24; +} + +bool equal_signatures(const unsigned char *data1, const unsigned char *data2) +{ + for (unsigned char i=0; i < 8; i++) { + if (data1[i] != data2[i]) return false; + } + return true; +} + +bool is_erased(const unsigned char *data, unsigned int len) +{ + while (len > 0) { + if (*data++ != 255) return false; + len = len - 1; + } + return true; +} + + +void printbuf(const void *buf, uint32_t len) +{ + const uint8_t *p = (const uint8_t *)buf; + do { + unsigned char b = *p++; + Serial.print(b >> 4, HEX); + Serial.print(b & 15, HEX); + //Serial.printf("%02X", *p++); + Serial.print(" "); + } while (--len > 0); + Serial.println(); +} + diff --git a/libraries/SerialFlash/keywords.txt b/libraries/SerialFlash/keywords.txt new file mode 100644 index 00000000..1e473961 --- /dev/null +++ b/libraries/SerialFlash/keywords.txt @@ -0,0 +1,9 @@ +SerialFlash KEYWORD1 +SerialFlashFile KEYWORD1 +createWritable KEYWORD2 +erase KEYWORD2 +eraseAll KEYWORD2 +ready KEYWORD2 +create KEYWORD2 +createWritable KEYWORD2 +getAddress KEYWORD2 diff --git a/libraries/SerialFlash/util/SerialFlash_directwrite.h b/libraries/SerialFlash/util/SerialFlash_directwrite.h new file mode 100644 index 00000000..d323a055 --- /dev/null +++ b/libraries/SerialFlash/util/SerialFlash_directwrite.h @@ -0,0 +1,204 @@ +#ifndef SerialFlash_directwrite_h +#define SerialFlash_directwrite_h + +#include + +// Adapted from OneWire.h + +#if ARDUINO >= 100 +#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc +#else +#include "WProgram.h" // for delayMicroseconds +#include "pins_arduino.h" // for digitalPinToBitMask, etc +#endif + +// Platform specific I/O definitions + +#if defined(__AVR__) +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM asm("r30") +#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) + +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (1) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (*((base)+512)) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1) + +#elif defined(__MKL26Z64__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask)) + +#elif defined(__SAM3X8E__) +#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask)) +#ifndef PROGMEM +#define PROGMEM +#endif +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const uint8_t *)(addr)) +#endif + +#elif defined(__PIC32MX__) +#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10 +#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08 +#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04 +#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24 +#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28 + +#elif defined(ARDUINO_ARCH_ESP8266) +#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO) +#define PIN_TO_BITMASK(pin) (1 << pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS +#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS +#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS +#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS +#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS + +#elif defined(__SAMD21G18A__) +#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask)) + +#elif defined(RBL_NRF51822) +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM +#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin) +#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin) +#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin) +#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL) +#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin) + +#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ + +#include "scss_registers.h" +#include "portable.h" +#include "avr/pgmspace.h" + +#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) +#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) +#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) +#define DIR_OFFSET_SS 0x01 +#define DIR_OFFSET_SOC 0x04 +#define EXT_PORT_OFFSET_SS 0x0A +#define EXT_PORT_OFFSET_SOC 0x50 + +/* GPIO registers base address */ +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) +#define PIN_TO_BITMASK(pin) pin +#define IO_REG_TYPE uint32_t +#define IO_REG_ASM + +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + IO_REG_TYPE ret; + if (SS_GPIO == GPIO_TYPE(pin)) { + ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); + } else { + ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); + } + return ((ret >> GPIO_ID(pin)) & 0x01); +} + +static inline __attribute__((always_inline)) +void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin)); + } +} + +#define DIRECT_READ(base, pin) directRead(base, pin) +#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) +#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) +#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) +#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) + +#else +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE unsigned int +#define IO_REG_ASM +#define DIRECT_READ(base, pin) digitalRead(pin) +#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW) +#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH) +#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT) +#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT) + +#endif + +#endif From 874c3ef08bf7031a06248abbb59274da740444f2 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Fri, 20 May 2016 10:38:55 -0700 Subject: [PATCH 042/222] SPI: add SPI1 to keywords.txt --- libraries/SPI/keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/SPI/keywords.txt b/libraries/SPI/keywords.txt index fa761658..ff058279 100644 --- a/libraries/SPI/keywords.txt +++ b/libraries/SPI/keywords.txt @@ -7,6 +7,7 @@ ####################################### SPI KEYWORD1 +SPI1 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) From 048800b47b8edcbe0cbf9401163ace1f4c15bb3e Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Thu, 19 May 2016 11:36:38 -0700 Subject: [PATCH 043/222] Jira-599. Routine, dtostrf, did not work with the latest toolchain. The call to sprintf in the routine crashed the system. Issue corrected by replacing the call. The routine, printfloat, in Print.cpp, is now usint dtostrf to print out double and float values. --- cores/arduino/Print.cpp | 60 +------------------ cores/arduino/stdlib_noniso.cpp | 103 ++++++++++++++++++-------------- cores/arduino/stdlib_noniso.h | 2 +- 3 files changed, 63 insertions(+), 102 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 2e5a5352..e5c95534 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -288,62 +288,8 @@ size_t Print::printLongLong(unsigned long long n, uint8_t base) { size_t Print::printFloat(double number, uint8_t digits) { - size_t n = 0; - int exponent = 0; - double tmp; - - if (isnan(number)) return print("nan"); - if (isinf(number)) return print("inf"); - - // Handle negative numbers - if (number < 0.0) { - n += print('-'); - number = -number; - } - - // Chk if integer part has more than 8 digits. - tmp = number; - while (true) { - tmp /= 10.0; - exponent++; - if (tmp < 10.0) break; - } - if (exponent > 8) - number = tmp; - else - exponent = 0; - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for (uint8_t i=0; i 0) { - n += print("."); - } - - // Extract digits from the remainder one at a time - while (digits-- > 0) - { - remainder *= 10.0; - int toPrint = int(remainder); - n += print(toPrint); - remainder -= toPrint; - } + char str[50]; - // Print the exponent portion - if (exponent) { - n += print("e+"); - n += print(exponent); - } - - return n; + dtostrf(number, 0, digits, str); + return(print(str)); } diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 53225e91..1fdf89c1 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -147,7 +147,22 @@ char* ultoa( unsigned long val, char *string, int radix ) return string; } -char * dtostrf(double number, unsigned char width, unsigned char prec, char *s) { +void shiftOutDigit(double *number, int count, char *s) +{ + double tmp = *number; + int digit; + + while( count ) { + tmp *= 10.0; + digit = (int)tmp; + *s++ = '0' + digit; + tmp -= (double)digit; + count--; + } + *number = tmp; +} + +char * dtostrf(double number, signed char width, unsigned char prec, char *s) { if (isnan(number)) { strcpy(s, "nan"); @@ -158,62 +173,62 @@ char * dtostrf(double number, unsigned char width, unsigned char prec, char *s) return s; } - char* out = s; - int exponent = 0; - unsigned char len, expLen; - double tmp; + char *out = s; + int expCnt = 0, digit, totalWidth; + double tmp, rounding; + + // Check for left adjustment (spaces) + while(width < 0) { + *out++ = ' '; + width++; + } + totalWidth = (int)width; // Handle negative numbers if (number < 0.0) { *out++ = '-'; number = -number; + if(totalWidth > 0) totalWidth--; } - // The integer portion has to be <= 8 digits. Otherwise, the - // string is in exponent format. + // Rounding up to the precision tmp = number; - for (;;) { + rounding = 0.5; + for(int i=0; i < prec; i++) + rounding /= 10.0; + tmp += rounding; + + // Shifting the number to the right + while( tmp >= 10.0 ) { tmp /= 10.0; - exponent++; - if (tmp < 10.0) break; + expCnt++; } - if (exponent > 8) - number = tmp; - else - exponent = 0; - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for (uint8_t i = 0; i < prec; ++i) - rounding /= 10.0; - - number += rounding; - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long)number; - double remainder = number - (double)int_part; - out += sprintf(out, "%ld", int_part); - - // Don't go beyond the given width of the string - len = (unsigned char)(out - s); - expLen = (exponent == 0) ? 0 : 5; // 5 places for exponent expression - if ((prec + len + expLen) > width) - prec = width - len - expLen; - - // Print the decimal point, but only if there are digits beyond - if (prec > 0) { - *out++ = '.'; - // Copy character by character to 'out' string - for (unsigned char decShift = prec; decShift > 0; decShift--) { - remainder *= 10.0; - out += sprintf(out, "%d", (int)remainder); - remainder -= (double)(int)remainder; - } + // 1st, print the single digit left after shifting + digit = (int)tmp; + *out++ = '0' + digit; + tmp -= (double)digit; + if(totalWidth > 0) totalWidth--; + + // Then the integer portion + shiftOutDigit(&tmp, expCnt, out); + out += expCnt; + if(totalWidth > 0) totalWidth -= expCnt; + + // Then the decimal portion + if( prec ) { + *out++ = '.'; + shiftOutDigit(&tmp, prec, out); + if(totalWidth > 0) totalWidth -= (prec + 1); + out += prec; } - // Print the exponent if exists - if (exponent) - sprintf(out, "e+%.3d", exponent); + // Right adjustment + while(totalWidth > 0) { + *out++ = ' '; + totalWidth--; + } + *out = 0; // End of string return s; } diff --git a/cores/arduino/stdlib_noniso.h b/cores/arduino/stdlib_noniso.h index 1d0d8d06..13b02887 100644 --- a/cores/arduino/stdlib_noniso.h +++ b/cores/arduino/stdlib_noniso.h @@ -37,7 +37,7 @@ char* utoa (unsigned int val, char *s, int radix); char* ultoa (unsigned long val, char *s, int radix); -char* dtostrf (double val, unsigned char width, unsigned char prec, char *s); +char* dtostrf (double val, signed char width, unsigned char prec, char *s); #ifdef __cplusplus } // extern "C" From 9472c9aa9427030f3e24968d4915fdf69881ea66 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Wed, 25 May 2016 15:43:28 -0700 Subject: [PATCH 044/222] Remove unnecessary #undefs -Remove #undefs from CurieSoftwareSerial Library -Because it was braking some functionality such abs() --- libraries/CurieSoftwareSerial/src/SoftwareSerial.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/CurieSoftwareSerial/src/SoftwareSerial.h b/libraries/CurieSoftwareSerial/src/SoftwareSerial.h index fb646b36..8e97cf79 100644 --- a/libraries/CurieSoftwareSerial/src/SoftwareSerial.h +++ b/libraries/CurieSoftwareSerial/src/SoftwareSerial.h @@ -96,13 +96,4 @@ class SoftwareSerial : public Stream }; -// Arduino 0012 workaround -#undef int -#undef char -#undef long -#undef byte -#undef float -#undef abs -#undef round - #endif From b8ea343bb237762de6ee3a60ba0b1e8d5af12ff0 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Thu, 26 May 2016 13:51:06 -0700 Subject: [PATCH 045/222] Fix some issues with printing float and double -fixes some issues with printing float and double -limits the number of decimal places printable to 16 --- cores/arduino/Print.cpp | 21 +++++++++++++++++---- cores/arduino/Print.h | 6 +++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index e5c95534..4faf9bd9 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -286,10 +286,23 @@ size_t Print::printLongLong(unsigned long long n, uint8_t base) { } -size_t Print::printFloat(double number, uint8_t digits) +size_t Print::printFloat(double number, uint16_t decimalPlaces) { - char str[50]; - - dtostrf(number, 0, digits, str); + if(decimalPlaces>16) + decimalPlaces = 16; + int digits = 0; + int intValue = (int)number; + while(intValue !=0) + { + intValue /= 10; + digits++; + } + digits += decimalPlaces; + if(number < 0) + digits++; + char str[digits]; + + + dtostrf(number, 0, digits-1, str); return(print(str)); } diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index 16552079..ed7bd7cc 100644 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -37,7 +37,7 @@ class Print int write_error; size_t printNumber(unsigned long, uint8_t); size_t printLongLong(unsigned long long, uint8_t); - size_t printFloat(double, uint8_t); + size_t printFloat(double, uint16_t); protected: void setWriteError(int err = 1) { write_error = err; } public: @@ -67,7 +67,7 @@ class Print size_t print(long long, int = DEC); size_t print(unsigned long, int = DEC); size_t print(unsigned long long, int = DEC); - size_t print(double, int = BIN); + size_t print(double, int = 2); size_t print(const Printable&); size_t println(const __FlashStringHelper *); @@ -81,7 +81,7 @@ class Print size_t println(long long, int = DEC); size_t println(unsigned long, int = DEC); size_t println(unsigned long long, int = DEC); - size_t println(double, int = BIN); + size_t println(double, int = 2); size_t println(const Printable&); size_t println(void); }; From ce7825883b79bd6849cc1fba4bbaa6416e43229d Mon Sep 17 00:00:00 2001 From: caihongm Date: Fri, 27 May 2016 02:17:19 +0800 Subject: [PATCH 046/222] Jira509:add IMU examples:FreeFallDetection, MotionDetection,ZeroMotionDetection; change CurieIMU.cpp line490 from 'setZeroMotionDetectionThreshold' to 'setZeroMtionDetectionDuration' --- .../FreeFallDetect/FreeFallDetect.ino | 63 ++++++++++++++++ .../examples/MotionDetect/MotionDetect.ino | 74 +++++++++++++++++++ .../ZeroMotionDetect/ZeroMotionDetect.ino | 60 +++++++++++++++ libraries/CurieIMU/src/CurieIMU.cpp | 2 +- 4 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino create mode 100644 libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino create mode 100644 libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino diff --git a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino new file mode 100644 index 00000000..e98ae66e --- /dev/null +++ b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino @@ -0,0 +1,63 @@ +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ + +/* + This sketch example demonstrates how the BMI160 accelerometer on the + Intel(R) Curie(TM) module can be used to detect free fall events +*/ + +#include "CurieIMU.h" + +boolean blinkState = false; // state of the LED +unsigned long loopTime = 0; // get the time since program started +unsigned long interruptsTime = 0; // get the time when free fall event is detected + + +void setup() { + Serial.begin(9600); + while(!Serial); // wait for the serial port to open + + /* Initialise the IMU */ + CurieIMU.begin(); + CurieIMU.attachInterrupt(eventCallback); + + /* Enable Free Fall Detection */ + CurieIMU.setDetectionThreshold(CURIE_IMU_FREEFALL, 1000); // 1g=1000mg + CurieIMU.setDetectionDuration(CURIE_IMU_FREEFALL, 50); // 50ms + CurieIMU.interrupts(CURIE_IMU_FREEFALL); + + Serial.println("IMU initialisation complete, waiting for events..."); +} + +void loop() { + // if free fall event is detected in 1000ms, LED will be turned up + loopTime = millis(); + if(abs(loopTime -interruptsTime) < 1000 ) + blinkState = true; + else + blinkState = false; + digitalWrite(13, blinkState); +} + +static void eventCallback(){ + if (CurieIMU.getInterruptStatus(CURIE_IMU_FREEFALL)) { + Serial.println("free fall detected! "); + interruptsTime = millis(); + } +} diff --git a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino new file mode 100644 index 00000000..54c97909 --- /dev/null +++ b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino @@ -0,0 +1,74 @@ +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ + +/* + This sketch example demonstrates how the BMI160 accelerometer on the + Intel(R) Curie(TM) module can be used to detect motion events +*/ + +#include "CurieIMU.h" + +boolean blinkState = false; // state of the LED +unsigned long loopTime = 0; // get the time since program started +unsigned long interruptsTime = 0; // get the time when motion event is detected + +void setup() { + Serial.begin(9600); + while(!Serial); // wait for the serial port to open + + /* Initialise the IMU */ + CurieIMU.begin(); + CurieIMU.attachInterrupt(eventCallback); + + /* Enable Motion Detection */ + CurieIMU.setDetectionThreshold(CURIE_IMU_MOTION, 20); // 20mg + CurieIMU.setDetectionDuration(CURIE_IMU_MOTION, 10); // trigger times of consecutive slope data points + CurieIMU.interrupts(CURIE_IMU_MOTION); + + Serial.println("IMU initialisation complete, waiting for events..."); +} + +void loop() { + // if motion is detected in 1000ms, LED will be turned up + loopTime = millis(); + if(abs(loopTime -interruptsTime) < 1000 ) + blinkState = true; + else + blinkState = false; + digitalWrite(13, blinkState); +} + + +static void eventCallback(void){ + if (CurieIMU.getInterruptStatus(CURIE_IMU_MOTION)) { + if (CurieIMU.motionDetected(X_AXIS, POSITIVE)) + Serial.println("Negative motion detected on X-axis"); + if (CurieIMU.motionDetected(X_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on X-axis"); + if (CurieIMU.motionDetected(Y_AXIS, POSITIVE)) + Serial.println("Negative motion detected on Y-axis"); + if (CurieIMU.motionDetected(Y_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on Y-axis"); + if (CurieIMU.motionDetected(Z_AXIS, POSITIVE)) + Serial.println("Negative motion detected on Z-axis"); + if (CurieIMU.motionDetected(Z_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on Z-axis"); + interruptsTime = millis(); + } +} diff --git a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino new file mode 100644 index 00000000..0d061c52 --- /dev/null +++ b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino @@ -0,0 +1,60 @@ +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ + +/* + This sketch example demonstrates how the BMI160 accelerometer on the + Intel(R) Curie(TM) module can be used to detect zero motion events +*/ +#include "CurieIMU.h" + +boolean blinkState = false; // state of the LED +unsigned long loopTime = 0; // get the time since program started +unsigned long interruptsTime = 0; // get the time when zero motion event is detected +void setup() { + Serial.begin(9600); + while(!Serial); // wait for the serial port to open + + /* Initialise the IMU */ + blinkState = CurieIMU.begin(); + CurieIMU.attachInterrupt(eventCallback); + + /* Enable Zero Motion Detection */ + CurieIMU.setDetectionThreshold(CURIE_IMU_ZERO_MOTION, 1500); // 1.5g=1500mg + CurieIMU.setDetectionDuration(CURIE_IMU_ZERO_MOTION, 25); // 25s + CurieIMU.interrupts(CURIE_IMU_ZERO_MOTION); + + Serial.println("IMU initialisation complete, waiting for events..."); +} + +void loop() { + //if zero motion is detected in 1500ms, LED will be turned up + loopTime = millis(); + if(abs(loopTime -interruptsTime) < 1500) + blinkState = true; + else + blinkState = false; + digitalWrite(13, blinkState); +} + +static void eventCallback(void){ + if (CurieIMU.getInterruptStatus(CURIE_IMU_ZERO_MOTION)) { + interruptsTime = millis(); + Serial.println("zero motion detected..."); + } +} diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index 12141325..d397121a 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -487,7 +487,7 @@ float CurieIMUClass::getDetectionDuration(int feature) return getTapShockDuration(); case CURIE_IMU_ZERO_MOTION: - return getZeroMotionDetectionThreshold(); + return getZeroMotionDetectionDuration(); case CURIE_IMU_TAP_QUIET: return getTapQuietDuration(); From 348e36ee6e6eb2c5f5687b642f978aabcace5be2 Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Thu, 26 May 2016 15:54:08 -0700 Subject: [PATCH 047/222] Jira-602: Convert float and double to strings. Output string is padded with spaces. --- cores/arduino/WString.cpp | 50 ++++++++++++++++++++++++++++++++------- cores/arduino/WString.h | 4 ++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index ec03d1ae..996aebca 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -133,16 +133,24 @@ String::String(unsigned long long value, unsigned char base) String::String(float value, unsigned char decimalPlaces) { + int len = digitsBe4Decimal(value); init(); - char buf[33]; - *this = dtostrf(value, (33 - 1), decimalPlaces, buf); + + if(decimalPlaces) len = 1 + ((int)decimalPlaces & 0x0FF); + + char buf[len+1]; + *this = dtostrf(value, 0, decimalPlaces, buf); } String::String(double value, unsigned char decimalPlaces) { + int len = digitsBe4Decimal(value); init(); - char buf[33]; - *this = dtostrf(value, (33 - 1), decimalPlaces, buf); + + if(decimalPlaces) len = 1 + ((int)decimalPlaces & 0x0FF); + + char buf[len+1]; + *this = dtostrf(value, 0, decimalPlaces, buf); } String::~String() @@ -362,15 +370,17 @@ unsigned char String::concat(unsigned long long num) unsigned char String::concat(float num) { - char buf[20]; - char* string = dtostrf(num, (20 - 1), 2, buf); + int len = digitsBe4Decimal(num); + char buf[len+1+2+1]; // The integer portion, 1 decimal point, 2 precision and 1 null char + char* string = dtostrf(num, 0, 2, buf); return concat(string, strlen(string)); } unsigned char String::concat(double num) { - char buf[20]; - char* string = dtostrf(num, (20 - 1), 2, buf); + int len = digitsBe4Decimal(num); + char buf[len+1+2+1]; // The integer portion, 1 decimal point, 2 precision and 1 null char + char* string = dtostrf(num, 0, 2, buf); return concat(string, strlen(string)); } @@ -797,3 +807,27 @@ float String::toFloat(void) const if (buffer) return float(atof(buffer)); return 0; } + +/*********************************************/ +/* utilities functions */ +/*********************************************/ + +int String::digitsBe4Decimal(double number) +{ + int cnt = 0; + long tmp = (long)number; // Drop the decimal here + + // Count -ve sign as one digit + if(tmp < 0) { + cnt++; + tmp = -tmp; + } + + // Count the number of digit + while(tmp) { + tmp /= 10; + cnt++; + } + return cnt; +} + diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 75a3e143..1367d0ab 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -217,6 +217,10 @@ class String #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void move(String &rhs); #endif + + // utilities functions. + // Number of digits (including sign) in the integer portion of a float/double + int digitsBe4Decimal(double number); }; class StringSumHelper : public String From f33e362db41f7871a63bc8f0294ce9aa43be3f0d Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Fri, 27 May 2016 14:26:46 -0700 Subject: [PATCH 048/222] Add category to Wire/library.properties --- libraries/Wire/library.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index 737ced11..99ff1b1d 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -7,4 +7,5 @@ sentence=This library allows you to communicate with I2C and Two Wire Interface paragraph=This library is compatible with Curie Core. It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line). url=http://makers.intel.com architectures=arc32 +category=Communication core-dependencies=arduino (>=1.6.3) From 4294ca5ad86c2f7f5cfb354ac193ff1ecbfc9fa9 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Fri, 27 May 2016 14:36:36 -0700 Subject: [PATCH 049/222] Remove SPI.set* calls from SerialFlash example These functions are not implemented for A101's SPI library. Remove these calls from examples/CopyFromSerial.ino --- .../examples/CopyFromSerial/CopyFromSerial.ino | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino b/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino index 703ac142..d7c4f376 100644 --- a/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino +++ b/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino @@ -79,11 +79,6 @@ #define BYTE_ESCAPE 0x7d #define BYTE_SEPARATOR 0x7c - -//SPI Pins (these are the values on the Audio board; change them if you have different ones) -#define MOSI 7 -#define MISO 12 -#define SCK 14 #define CSPIN 21 void setup(){ @@ -91,10 +86,6 @@ void setup(){ pinMode(13, OUTPUT); - //Set up SPI - SPI.setMOSI(MOSI); - SPI.setMISO(MISO); - SPI.setSCK(SCK); SerialFlash.begin(CSPIN); //We start by formatting the flash... From 409e4b07f477e6345c972a40376085c89ecdb46e Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Fri, 27 May 2016 14:38:05 -0700 Subject: [PATCH 050/222] Remove unsupported SerialFlash example CopyFromSD.ino requires SDfatlib (for AVR boards) which is unsupported. --- .../examples/CopyFromSD/CopyFromSD.ino | 133 ------------------ 1 file changed, 133 deletions(-) delete mode 100644 libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino diff --git a/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino b/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino deleted file mode 100644 index ff91b828..00000000 --- a/libraries/SerialFlash/examples/CopyFromSD/CopyFromSD.ino +++ /dev/null @@ -1,133 +0,0 @@ -// SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash - -#include -#include -#include - -const int SDchipSelect = 4; // Audio Shield has SD card CS on pin 10 -const int FlashChipSelect = 21; // digital pin for flash chip CS pin - -void setup() { - //uncomment these if using Teensy audio shield - //SPI.setSCK(14); // Audio shield has SCK on pin 14 - //SPI.setMOSI(7); // Audio shield has MOSI on pin 7 - - //uncomment these if you have other SPI chips connected - //to keep them disabled while using only SerialFlash - //pinMode(4, INPUT_PULLUP); - //pinMode(10, INPUT_PULLUP); - - Serial.begin(9600); - - // wait up to 10 seconds for Arduino Serial Monitor - unsigned long startMillis = millis(); - while (!Serial && (millis() - startMillis < 10000)) ; - delay(100); - Serial.println("Copy all files from SD Card to SPI Flash"); - - if (!SD.begin(SDchipSelect)) { - error("Unable to access SD card"); - } - if (!SerialFlash.begin(FlashChipSelect)) { - error("Unable to access SPI Flash chip"); - } - - int count = 0; - File rootdir = SD.open("/"); - while (1) { - // open a file from the SD card - Serial.println(); - File f = rootdir.openNextFile(); - if (!f) break; - const char *filename = f.name(); - Serial.print(filename); - Serial.print(" "); - unsigned long length = f.size(); - Serial.println(length); - - // check if this file is already on the Flash chip - if (SerialFlash.exists(filename)) { - Serial.println(" already exists on the Flash chip"); - SerialFlashFile ff = SerialFlash.open(filename); - if (ff && ff.size() == f.size()) { - Serial.println(" size is the same, comparing data..."); - if (compareFiles(f, ff) == true) { - Serial.println(" files are identical :)"); - f.close(); - ff.close(); - continue; // advance to next file - } else { - Serial.println(" files are different"); - } - } else { - Serial.print(" size is different, "); - Serial.print(ff.size()); - Serial.println(" bytes"); - } - // delete the copy on the Flash chip, if different - Serial.println(" delete file from Flash chip"); - SerialFlash.remove(filename); - } - - // create the file on the Flash chip and copy data - if (SerialFlash.create(filename, length)) { - SerialFlashFile ff = SerialFlash.open(filename); - if (ff) { - Serial.print(" copying"); - // copy data loop - unsigned long count = 0; - unsigned char dotcount = 9; - while (count < length) { - char buf[256]; - unsigned int n; - n = f.read(buf, 256); - ff.write(buf, n); - count = count + n; - Serial.print("."); - if (++dotcount > 100) { - Serial.println(); - dotcount = 0; - } - } - ff.close(); - if (dotcount > 0) Serial.println(); - } else { - Serial.println(" error opening freshly created file!"); - } - } else { - Serial.println(" unable to create file"); - } - f.close(); - } - rootdir.close(); - delay(10); - Serial.println("Finished All Files"); -} - - -bool compareFiles(File &file, SerialFlashFile &ffile) { - file.seek(0); - ffile.seek(0); - unsigned long count = file.size(); - while (count > 0) { - char buf1[128], buf2[128]; - unsigned long n = count; - if (n > 128) n = 128; - file.read(buf1, n); - ffile.read(buf2, n); - if (memcmp(buf1, buf2, n) != 0) return false; // differ - count = count - n; - } - return true; // all data identical -} - - -void loop() { -} - -void error(const char *message) { - while (1) { - Serial.println(message); - delay(2500); - } -} From acc4b38ba43d654992b72fa9d4afa68b834a098c Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Tue, 31 May 2016 16:12:32 -0700 Subject: [PATCH 051/222] Revert "Fix some issues with printing float and double" This reverts commit b8ea343bb237762de6ee3a60ba0b1e8d5af12ff0. --- cores/arduino/Print.cpp | 21 ++++----------------- cores/arduino/Print.h | 6 +++--- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 4faf9bd9..e5c95534 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -286,23 +286,10 @@ size_t Print::printLongLong(unsigned long long n, uint8_t base) { } -size_t Print::printFloat(double number, uint16_t decimalPlaces) +size_t Print::printFloat(double number, uint8_t digits) { - if(decimalPlaces>16) - decimalPlaces = 16; - int digits = 0; - int intValue = (int)number; - while(intValue !=0) - { - intValue /= 10; - digits++; - } - digits += decimalPlaces; - if(number < 0) - digits++; - char str[digits]; - - - dtostrf(number, 0, digits-1, str); + char str[50]; + + dtostrf(number, 0, digits, str); return(print(str)); } diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index ed7bd7cc..16552079 100644 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -37,7 +37,7 @@ class Print int write_error; size_t printNumber(unsigned long, uint8_t); size_t printLongLong(unsigned long long, uint8_t); - size_t printFloat(double, uint16_t); + size_t printFloat(double, uint8_t); protected: void setWriteError(int err = 1) { write_error = err; } public: @@ -67,7 +67,7 @@ class Print size_t print(long long, int = DEC); size_t print(unsigned long, int = DEC); size_t print(unsigned long long, int = DEC); - size_t print(double, int = 2); + size_t print(double, int = BIN); size_t print(const Printable&); size_t println(const __FlashStringHelper *); @@ -81,7 +81,7 @@ class Print size_t println(long long, int = DEC); size_t println(unsigned long, int = DEC); size_t println(unsigned long long, int = DEC); - size_t println(double, int = 2); + size_t println(double, int = BIN); size_t println(const Printable&); size_t println(void); }; From e792ba2bd6480a556e50259e0e836ae4cf5ec371 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Tue, 31 May 2016 17:03:06 -0700 Subject: [PATCH 052/222] Fix bug when using StringConstructor with doubles -Fixes issue of StringContructor instability with doubles --- cores/arduino/WString.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 996aebca..eaa901a4 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -136,7 +136,7 @@ String::String(float value, unsigned char decimalPlaces) int len = digitsBe4Decimal(value); init(); - if(decimalPlaces) len = 1 + ((int)decimalPlaces & 0x0FF); + if(decimalPlaces) len += 1 + ((int)decimalPlaces & 0x0FF); char buf[len+1]; *this = dtostrf(value, 0, decimalPlaces, buf); @@ -147,7 +147,7 @@ String::String(double value, unsigned char decimalPlaces) int len = digitsBe4Decimal(value); init(); - if(decimalPlaces) len = 1 + ((int)decimalPlaces & 0x0FF); + if(decimalPlaces) len += 1 + ((int)decimalPlaces & 0x0FF); char buf[len+1]; *this = dtostrf(value, 0, decimalPlaces, buf); From c27462cbc168257c2c928d435dcaf3b43a535fe1 Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Wed, 25 May 2016 07:30:23 +0800 Subject: [PATCH 053/222] JIRA-560 I2C Bus Scan using read instead of write to avoid sending the extra byte when scaning I2C bus --- cores/arduino/i2c.c | 36 +++++++++-- cores/arduino/i2c.h | 10 ++- libraries/Wire/examples/bus_scan/bus_scan.ino | 63 +++++++++++++++++++ libraries/Wire/src/Wire.cpp | 30 +++++---- system/libarc32_arduino101/drivers/i2c_priv.h | 1 + .../libarc32_arduino101/drivers/ss_dw_i2c.c | 7 +++ .../drivers/ss_i2c_iface.c | 7 +++ 7 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 libraries/Wire/examples/bus_scan/bus_scan.ino diff --git a/cores/arduino/i2c.c b/cores/arduino/i2c.c index 1a674fee..9e6dc4b2 100644 --- a/cores/arduino/i2c.c +++ b/cores/arduino/i2c.c @@ -28,6 +28,7 @@ static volatile uint8_t i2c_tx_complete; static volatile uint8_t i2c_rx_complete; static volatile uint8_t i2c_err_detect; +static volatile uint32_t i2c_err_source; static volatile uint8_t i2c_slave = 0; @@ -44,13 +45,25 @@ static void ss_i2c_tx(uint32_t dev_id) static void ss_i2c_err(uint32_t dev_id) { i2c_err_detect = 1; + i2c_err_source = dev_id; } static int wait_rx_or_err(bool no_stop){ uint64_t timeout = TIMEOUT_MS; while(timeout--) { if (i2c_err_detect) { - return I2C_ERROR; + if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) + { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } + else if (i2c_err_source & I2C_ABRT_TXDATA_NOACK ) + { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } + else + { + return I2C_ERROR_OTHER; // other error + } } if (!no_stop) { if (i2c_rx_complete) { @@ -69,7 +82,18 @@ static int wait_tx_or_err(bool no_stop){ uint64_t timeout = TIMEOUT_MS; while(timeout--) { if (i2c_err_detect) { - return I2C_ERROR; + if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) + { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } + else if (i2c_err_source & I2C_ABRT_TXDATA_NOACK ) + { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } + else + { + return I2C_ERROR_OTHER; // other error + } } if (!no_stop) { if (i2c_tx_complete) { @@ -86,8 +110,9 @@ static int wait_tx_or_err(bool no_stop){ static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ uint64_t timeout = TIMEOUT_MS; + int ret = 0; while(timeout--) { - int ret = ss_i2c_status(controller_id, no_stop); + ret = ss_i2c_status(controller_id, no_stop); if (ret == I2C_OK) { return I2C_OK; } @@ -95,7 +120,7 @@ static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ delay(1); } } - return I2C_TIMEOUT; + return I2C_TIMEOUT - ret; } @@ -122,6 +147,7 @@ int i2c_openadapter(void) i2c_tx_complete = 0; i2c_rx_complete = 0; i2c_err_detect = 0; + i2c_err_source = 0; ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg); ss_i2c_clock_enable(I2C_SENSING_0); @@ -142,6 +168,7 @@ int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop) i2c_tx_complete = 0; i2c_err_detect = 0; + i2c_err_source = 0; ss_i2c_transfer(I2C_SENSING_0, bytes, length, 0, 0, i2c_slave, no_stop); ret = wait_tx_or_err(no_stop); if (ret) @@ -158,6 +185,7 @@ int i2c_readbytes(uint8_t *buf, int length, bool no_stop) i2c_rx_complete = 0; i2c_err_detect = 0; + i2c_err_source = 0; ss_i2c_transfer(I2C_SENSING_0, 0, 0, buf, length, i2c_slave, no_stop); ret = wait_rx_or_err(no_stop); if (ret) diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index b3e305e0..684b54e5 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -28,8 +28,14 @@ extern "C"{ #endif #define I2C_OK 0 -#define I2C_TIMEOUT -1 -#define I2C_ERROR -2 +#define I2C_TIMEOUT -10 +#define I2C_ERROR -11 +#define I2C_ERROR_ADDRESS_NOACK (-2) +#define I2C_ERROR_DATA_NOACK (-3) +#define I2C_ERROR_OTHER (-4) + +#define I2C_ABRT_7B_ADDR_NOACK (1 << 0) +#define I2C_ABRT_TXDATA_NOACK (1 << 3) int i2c_openadapter(void); void i2c_setslave(uint8_t addr); diff --git a/libraries/Wire/examples/bus_scan/bus_scan.ino b/libraries/Wire/examples/bus_scan/bus_scan.ino new file mode 100644 index 00000000..11e39373 --- /dev/null +++ b/libraries/Wire/examples/bus_scan/bus_scan.ino @@ -0,0 +1,63 @@ +/* + Sketch: I2CBusScan.ino + + This sketch demonstrates the usage of the Curie Wire Library. + It scan the I2C bus to find slave devices + + You can see the found I2C slave device shown in serial output + with the following message: + address:xxx found + + created by Intel + Modified 18 May 2016 + + This example code is in the public domain. +*/ + + +#include + +byte startAddress = 1; // skip reserved address from 0 to 7 +byte endAddress = 127; + +void I2CBusScan(byte startAddress, byte endAddress) +{ + byte retval; + char temp[64]; + for( byte address = startAddress; address <= endAddress; address++ ) { + Wire.beginTransmission(address); + retval = Wire.endTransmission(); + sprintf(temp, "address: %-4d%-5s", address, (retval == 0 || retval == 3) ? "found" : ""); + Serial.print(temp); + Serial.print((address % 4) ? '\t' : '\n'); + } +} + +void setup() +{ + // Initialize pin 13 as an output - onboard LED. + pinMode(13, OUTPUT); + + // join i2c bus (address optional for master) + Wire.begin(); + + Serial.begin(115200); +} + +boolean toggle = false; // state of the LED +void loop() +{ + toggle = !toggle; + digitalWrite(13, toggle); + delay(5000); + + Serial.print("Start I2C Bus Scan from "); + Serial.print(startAddress); + Serial.print(" to "); + Serial.print(endAddress); + Serial.println("....."); + + I2CBusScan( startAddress, endAddress); + + Serial.println("\ndone"); +} diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 423a9a3d..616e613e 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -107,22 +107,20 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) { int err; // transmit buffer (blocking) - if (txBufferLength >= 1) { - err = i2c_writebytes(txBuffer, txBufferLength, !sendStop); - } else { - //Workaround: I2C bus scan is currently implemented by sending an extra byte of value 0 - txBuffer[0] = 0; - err = i2c_writebytes(txBuffer, 1, !sendStop); - } - // empty buffer - txBufferLength = 0; - if (err < 0) { - return 2; // NACK on transmit of address - /* NOTE: This implementation currently does not distinguish - * between NACK on transmit of adddress or data, or other errors - */ - } - return 0; // success + if (txBufferLength >= 1) { + err = i2c_writebytes(txBuffer, txBufferLength, !sendStop); + } else { + uint8_t temp = 0; + // Workaround: I2C bus scan is currently implemented by reading, + // so set the read length to 0 to inform the lower I2C driver that we are doing bus scan + err = i2c_readbytes(&temp, 0, 0); + } + // empty buffer + txBufferLength = 0; + if (err < 0) { + return -err; + } + return 0; // success } // This provides backwards compatibility with the original diff --git a/system/libarc32_arduino101/drivers/i2c_priv.h b/system/libarc32_arduino101/drivers/i2c_priv.h index dc3620e9..d6bb585f 100644 --- a/system/libarc32_arduino101/drivers/i2c_priv.h +++ b/system/libarc32_arduino101/drivers/i2c_priv.h @@ -132,6 +132,7 @@ typedef struct i2c_info { uint32_t rx_tx_len; // tx_len + rx_len uint8_t *i2c_write_buff; uint8_t *i2c_read_buff; + uint8_t restart; /* Callbacks */ IO_CB_FUNC tx_cb; diff --git a/system/libarc32_arduino101/drivers/ss_dw_i2c.c b/system/libarc32_arduino101/drivers/ss_dw_i2c.c index d8b1813a..7f4b3b03 100644 --- a/system/libarc32_arduino101/drivers/ss_dw_i2c.c +++ b/system/libarc32_arduino101/drivers/ss_dw_i2c.c @@ -127,6 +127,11 @@ void i2c_fill_fifo(i2c_info_pt dev, bool no_stop) { // last dummy byte to write if(! no_stop) data |= I2C_STOP_CMD; + if(dev->restart) + { + data |= I2C_RESTART_CMD; + dev->restart = false; + } } } REG_WRITE( I2C_DATA_CMD, data ); @@ -166,6 +171,7 @@ void i2c_mst_err_ISR_proc(i2c_info_pt dev) if( status & R_TX_ABRT ) { dev->status_code = status; + dev->cb_err_data = REG_READ( I2C_TX_ABRT_SOURCE ); REG_WRITE( I2C_CLR_INTR, R_TX_ABRT ); REG_WRITE( I2C_INTR_MASK, I2C_INT_DSB ); dev->state = I2C_STATE_READY; @@ -177,6 +183,7 @@ void i2c_mst_err_ISR_proc(i2c_info_pt dev) if( (status & R_TX_OVER)||(status & R_RX_OVER) ) { dev->status_code = status; + dev->cb_err_data = REG_READ( I2C_TX_ABRT_SOURCE ); REG_WRITE( I2C_CLR_INTR, R_TX_OVER|R_RX_OVER ); REG_WRITE( I2C_INTR_MASK, I2C_INT_DSB ); dev->state = I2C_STATE_READY; diff --git a/system/libarc32_arduino101/drivers/ss_i2c_iface.c b/system/libarc32_arduino101/drivers/ss_i2c_iface.c index c237419b..200ed273 100644 --- a/system/libarc32_arduino101/drivers/ss_i2c_iface.c +++ b/system/libarc32_arduino101/drivers/ss_i2c_iface.c @@ -188,6 +188,7 @@ DRIVER_API_RC ss_i2c_set_config(I2C_CONTROLLER controller_id, i2c_cfg_data_t *co /* do some check here to see if this controller is accessible form this core */ dev = &i2c_master_devs[SS_CTRL_ID(controller_id)]; + dev->restart = false; i2c_handles[SS_CTRL_ID(controller_id)] = dev; /* enable clock to controller to allow reg writes */ @@ -346,6 +347,12 @@ DRIVER_API_RC ss_i2c_transfer(I2C_CONTROLLER controller_id, uint8_t *data_write, return DRV_RC_FAIL; } + if ((data_read_len == 0) && (data_write_len == 0)) + { + //Workaround: we know that we are doing I2C bus scan. + data_read_len = 1; + dev->restart = true; + } /* Protect registers using lock and unlock of interruptions */ saved = interrupt_lock(); From df3b675c1ba4113fa560078ae60f610f4d8b3ae0 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Fri, 3 Jun 2016 15:02:00 -0700 Subject: [PATCH 054/222] SerialFlash: enlarge chip ID buffer SerialFlashChip::readID() writes up to 5 bytes into the buffer provided, but the caller only allocates 3 bytes. Increase buffer size to 5 bytes. --- libraries/SerialFlash/SerialFlashDirectory.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/SerialFlash/SerialFlashDirectory.cpp b/libraries/SerialFlash/SerialFlashDirectory.cpp index 036a3c34..116c14ec 100644 --- a/libraries/SerialFlash/SerialFlashDirectory.cpp +++ b/libraries/SerialFlash/SerialFlashDirectory.cpp @@ -310,7 +310,9 @@ bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t ali // last check, if enough space exists... len = strlen(filename); // TODO: check for enough string space for filename - uint8_t id[3]; + + // 5 bytes, to allow for extra 2 bytes in Spansion device IDs + uint8_t id[5]; SerialFlash.readID(id); if (address + length > SerialFlash.capacity(id)) return false; From a694d09698db8d0f77ac19d58d1db34eef3d1b4d Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Tue, 7 Jun 2016 16:57:12 -0700 Subject: [PATCH 055/222] Jira-617: String Object constructor hangs up when handling large floating point number --- cores/arduino/WString.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index eaa901a4..02f8dffe 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -133,23 +133,23 @@ String::String(unsigned long long value, unsigned char base) String::String(float value, unsigned char decimalPlaces) { - int len = digitsBe4Decimal(value); + int totalSize = digitsBe4Decimal(value); init(); - if(decimalPlaces) len += 1 + ((int)decimalPlaces & 0x0FF); + if(decimalPlaces) totalSize += 1 + ((int)decimalPlaces & 0x0FF); - char buf[len+1]; + char buf[totalSize+1]; *this = dtostrf(value, 0, decimalPlaces, buf); } String::String(double value, unsigned char decimalPlaces) { - int len = digitsBe4Decimal(value); + int totalSize = digitsBe4Decimal(value); init(); - if(decimalPlaces) len += 1 + ((int)decimalPlaces & 0x0FF); + if(decimalPlaces) totalSize += 1 + ((int)decimalPlaces & 0x0FF); - char buf[len+1]; + char buf[totalSize+1]; *this = dtostrf(value, 0, decimalPlaces, buf); } @@ -814,18 +814,17 @@ float String::toFloat(void) const int String::digitsBe4Decimal(double number) { - int cnt = 0; - long tmp = (long)number; // Drop the decimal here + int cnt = 1; // Always has one digit // Count -ve sign as one digit - if(tmp < 0) { + if(number < 0.0) { cnt++; - tmp = -tmp; + number = -number; } - // Count the number of digit - while(tmp) { - tmp /= 10; + // Count the number of digits beyond the 1st, basically, the exponent. + while(number >= 10.0) { + number /= 10; cnt++; } return cnt; From de30a61b909802f2dbb3380c4adc9316ee1f64f7 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Mon, 13 Jun 2016 11:57:21 -0700 Subject: [PATCH 056/222] ATLEDGE-553 Modify library examples header info --- .../BatteryMonitor/BatteryMonitor.ino | 36 ++++++++++------- .../CurieBLE/examples/ButtonLED/ButtonLED.ino | 40 ++++++++++--------- .../examples/CallbackLED/CallbackLED.ino | 40 ++++++++++--------- libraries/CurieBLE/examples/LED/LED.ino | 35 +++++++++------- .../examples/Accelerometer/Accelerometer.ino | 39 ++++++++++-------- .../AccelerometerOrientation.ino | 37 +++++++++-------- .../FreeFallDetect/FreeFallDetect.ino | 35 +++++++++------- libraries/CurieIMU/examples/Gyro/Gyro.ino | 38 ++++++++++-------- .../examples/MotionDetect/MotionDetect.ino | 35 +++++++++------- .../examples/ShockDetect/ShockDetect.ino | 39 ++++++++++-------- .../CurieIMU/examples/StepCount/StepCount.ino | 39 ++++++++++-------- .../CurieIMU/examples/TapDetect/TapDetect.ino | 40 ++++++++++--------- .../TapDoubleDetect/TapDoubleDetect.ino | 39 ++++++++++-------- .../ZeroMotionDetect/ZeroMotionDetect.ino | 35 +++++++++------- .../CurieTime/examples/ReadTest/ReadTest.ino | 23 +++++++++++ .../CurieTime/examples/SetTime/SetTime.ino | 23 +++++++++++ 16 files changed, 342 insertions(+), 231 deletions(-) diff --git a/libraries/CurieBLE/examples/BatteryMonitor/BatteryMonitor.ino b/libraries/CurieBLE/examples/BatteryMonitor/BatteryMonitor.ino index f50bc51b..688b147f 100644 --- a/libraries/CurieBLE/examples/BatteryMonitor/BatteryMonitor.ino +++ b/libraries/CurieBLE/examples/BatteryMonitor/BatteryMonitor.ino @@ -1,20 +1,8 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - 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 -*/ #include /* @@ -98,3 +86,21 @@ void updateBatteryLevel() { oldBatteryLevel = batteryLevel; // save the level for next comparison } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieBLE/examples/ButtonLED/ButtonLED.ino b/libraries/CurieBLE/examples/ButtonLED/ButtonLED.ino index 5251a967..b4cd873a 100644 --- a/libraries/CurieBLE/examples/ButtonLED/ButtonLED.ino +++ b/libraries/CurieBLE/examples/ButtonLED/ButtonLED.ino @@ -1,22 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 -*/ - + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ #include @@ -83,3 +68,22 @@ void loop() { } } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieBLE/examples/CallbackLED/CallbackLED.ino b/libraries/CurieBLE/examples/CallbackLED/CallbackLED.ino index e918ddab..f8788731 100644 --- a/libraries/CurieBLE/examples/CallbackLED/CallbackLED.ino +++ b/libraries/CurieBLE/examples/CallbackLED/CallbackLED.ino @@ -1,22 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 -*/ - + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ #include @@ -84,3 +69,22 @@ void switchCharacteristicWritten(BLECentral& central, BLECharacteristic& charact digitalWrite(ledPin, LOW); } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieBLE/examples/LED/LED.ino b/libraries/CurieBLE/examples/LED/LED.ino index bd9af1b0..a55501dc 100644 --- a/libraries/CurieBLE/examples/LED/LED.ino +++ b/libraries/CurieBLE/examples/LED/LED.ino @@ -1,20 +1,8 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - 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 -*/ #include BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming) @@ -79,3 +67,20 @@ void loop() { } } +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino index 89bb0052..22069c61 100644 --- a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino +++ b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 on the @@ -68,3 +54,22 @@ float convertRawAcceleration(int aRaw) { return a; } +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ + diff --git a/libraries/CurieIMU/examples/AccelerometerOrientation/AccelerometerOrientation.ino b/libraries/CurieIMU/examples/AccelerometerOrientation/AccelerometerOrientation.ino index a36ee612..9a4ed069 100644 --- a/libraries/CurieIMU/examples/AccelerometerOrientation/AccelerometerOrientation.ino +++ b/libraries/CurieIMU/examples/AccelerometerOrientation/AccelerometerOrientation.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 on the @@ -97,4 +83,21 @@ int orientation = - 1; // the board's orientation } } +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino index e98ae66e..36786412 100644 --- a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino +++ b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino @@ -1,20 +1,6 @@ /* Copyright (c) 2016 Intel Corporation. All rights reserved. - - 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 - + See the bottom of this file for license terms. */ /* @@ -61,3 +47,22 @@ static void eventCallback(){ interruptsTime = millis(); } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/Gyro/Gyro.ino b/libraries/CurieIMU/examples/Gyro/Gyro.ino index 81fa30d7..a7752659 100644 --- a/libraries/CurieIMU/examples/Gyro/Gyro.ino +++ b/libraries/CurieIMU/examples/Gyro/Gyro.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 on the @@ -68,3 +54,21 @@ float convertRawGyro(int gRaw) { return g; } +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino index 54c97909..2eb8c9ac 100644 --- a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino +++ b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino @@ -1,20 +1,6 @@ /* Copyright (c) 2016 Intel Corporation. All rights reserved. - - 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 - + See the bottom of this file for license terms. */ /* @@ -72,3 +58,22 @@ static void eventCallback(void){ interruptsTime = millis(); } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino index 06c4a2e5..3d3bb656 100644 --- a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino +++ b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 accelerometer on the @@ -66,3 +52,22 @@ static void eventCallback(void) Serial.println("Positive shock detected on Z-axis"); } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/StepCount/StepCount.ino b/libraries/CurieIMU/examples/StepCount/StepCount.ino index d2096dff..386121b0 100644 --- a/libraries/CurieIMU/examples/StepCount/StepCount.ino +++ b/libraries/CurieIMU/examples/StepCount/StepCount.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 accelerometer on the @@ -86,3 +72,22 @@ static void eventCallback(void) { if (CurieIMU.stepsDetected()) updateStepCount(); } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino index abe21ae0..d0489a9a 100644 --- a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino +++ b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino @@ -1,21 +1,7 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ /* This sketch example demonstrates how the BMI160 accelerometer on the @@ -64,4 +50,22 @@ static void eventCallback() if (CurieIMU.tapDetected(Z_AXIS, POSITIVE)) Serial.println("Tap detected on positive Z-axis"); } -} \ No newline at end of file +} + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 +*/ diff --git a/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino index be7476a5..d8c63f4b 100644 --- a/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino +++ b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino @@ -1,20 +1,6 @@ /* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - 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 - + Copyright (c) 2016 Intel Corporation. All rights reserved. + See the bottom of this file for license terms. */ /* @@ -67,4 +53,23 @@ static void eventCallback() if (CurieIMU.tapDetected(Z_AXIS, POSITIVE)) Serial.println("Double Tap detected on positive Z-axis"); } -} \ No newline at end of file +} + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino index 0d061c52..9ac2cc65 100644 --- a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino +++ b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino @@ -1,20 +1,6 @@ /* Copyright (c) 2016 Intel Corporation. All rights reserved. - - 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 - + See the bottom of this file for full license terms. */ /* @@ -58,3 +44,22 @@ static void eventCallback(void){ Serial.println("zero motion detected..."); } } + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + 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 + +*/ diff --git a/libraries/CurieTime/examples/ReadTest/ReadTest.ino b/libraries/CurieTime/examples/ReadTest/ReadTest.ino index 8490ac7e..4483268f 100644 --- a/libraries/CurieTime/examples/ReadTest/ReadTest.ino +++ b/libraries/CurieTime/examples/ReadTest/ReadTest.ino @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + #include void setup() { @@ -31,3 +36,21 @@ void print2digits(int number) { } Serial.print(number); } + +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * 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 + */ diff --git a/libraries/CurieTime/examples/SetTime/SetTime.ino b/libraries/CurieTime/examples/SetTime/SetTime.ino index d63d2bb0..97dbefc6 100644 --- a/libraries/CurieTime/examples/SetTime/SetTime.ino +++ b/libraries/CurieTime/examples/SetTime/SetTime.ino @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + #include void setup() { @@ -36,3 +41,21 @@ void print2digits(int number) { } Serial.print(number); } + +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * + * 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 + */ From 2f5ae85f235bc1e5a0e5b50d63961f4348f237a0 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Mon, 13 Jun 2016 10:35:53 -0700 Subject: [PATCH 057/222] ATLEDGE-572: Fix getStepDetectionMode() This function is reading all 8 bits of RA_STEP_CONF_1 (0x7A-0x7B) to obtain a value for min_step_buf, though this value is only represented by the lower 3 bits; bit 4 is used as the 'enable' bit. As a consequence, this function will read the step detection mode incorrectly when step counting is enabled. Fix this by only reading the lower 3 bits of RA_STEP_CONF_1. --- libraries/CurieIMU/src/BMI160.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/CurieIMU/src/BMI160.cpp b/libraries/CurieIMU/src/BMI160.cpp index 842222bd..746e8123 100644 --- a/libraries/CurieIMU/src/BMI160.cpp +++ b/libraries/CurieIMU/src/BMI160.cpp @@ -824,7 +824,10 @@ uint8_t BMI160Class::getStepDetectionMode() { uint8_t ret_step_conf0, ret_min_step_buf; ret_step_conf0 = reg_read(BMI160_RA_STEP_CONF_0); - ret_min_step_buf = reg_read(BMI160_RA_STEP_CONF_1); + + /* min_step_buf is the first 3 bits of RA_STEP_CONF_1; the + * 4th bit is the enable bit (step_cnt_en) */ + ret_min_step_buf = reg_read_bits(BMI160_RA_STEP_CONF_1, 0, 3); if ((ret_step_conf0 == BMI160_RA_STEP_CONF_0_NOR) && (ret_min_step_buf == BMI160_RA_STEP_CONF_1_NOR)) return BMI160_STEP_MODE_NORMAL; From 20844ff46b455055f86641c785fb580ae1214222 Mon Sep 17 00:00:00 2001 From: Mike Duong Date: Wed, 25 May 2016 18:32:05 -0700 Subject: [PATCH 058/222] ATLEDGE-586: String.compareTo() does not compute the same as Uno for POS values --- cores/arduino/WString.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 02f8dffe..6217a311 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -502,7 +502,13 @@ int String::compareTo(const String &s) const if (buffer && len > 0) return *(unsigned char *)buffer; return 0; } - return strcmp(buffer, s.buffer); + const char *p1 = buffer; + const char *p2 = s.buffer; + + while (*p1 == *p2++) + if ('\0' == *p1++) + return 0; + return (*(const char *)p1 - *(const char *)(p2 - 1)); } unsigned char String::equals(const String &s2) const From 2cd33f43a1b84c3f23194b27290114c4cec5d9df Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 16 Jun 2016 11:29:06 +0200 Subject: [PATCH 059/222] Correct core version in platform.txt --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 9cec154c..5da7aad6 100644 --- a/platform.txt +++ b/platform.txt @@ -5,7 +5,7 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=Intel Curie (32-bit) Boards -version=1.0.3 +version=1.0.6 # Arduino 101 compile variables # ---------------------- From 4d9642871ae0bfb28783b1d6fa00b364ea201cf1 Mon Sep 17 00:00:00 2001 From: Oren Levy Date: Mon, 20 Jun 2016 14:59:09 -0700 Subject: [PATCH 060/222] Added MIDI examples --- .../CurieBLE/examples/MIDIBLE/MIDIBLE.ino | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 libraries/CurieBLE/examples/MIDIBLE/MIDIBLE.ino diff --git a/libraries/CurieBLE/examples/MIDIBLE/MIDIBLE.ino b/libraries/CurieBLE/examples/MIDIBLE/MIDIBLE.ino new file mode 100644 index 00000000..2dbe9833 --- /dev/null +++ b/libraries/CurieBLE/examples/MIDIBLE/MIDIBLE.ino @@ -0,0 +1,158 @@ +/* Written by Oren Levy (auxren.com; @auxren) while competing on + America's Greatest Makers with help from Intel. + MIDI over BLE info from: https://developer.apple.com/bluetooth/Apple-Bluetooth-Low-Energy-MIDI-Specification.pdf + + This sketch plays a random MIDI note (between 0 and 127) every 400ms. + For a 'smarter' sketch, check out my Airpeggiator example. + The Airpeggiator uses the Curie's IMU to allow you to play + an imaginary harp in the air. I included a quantizer so you can + select a key and scale so you can jam along with friends. + https://github.com/auxren/MIDIBLE101/tree/master/Airpeggiator + + I have only tested MIDI over BLE using Apple devices. Android doesn't + support native MIDI over BLE yet and I haven't had much of a chance + to test with Windows machines. + + To connect on a Mac, search for Audio MIDI Setup. + Click 'Window' on the top menu and choose 'Show MIDI Studio'. + Double click 'Bluetooth' and the bluetooth configuration window + will pop up. After loading the MIDIBLE sketch on your Arduino 101 + you should see it advertising as Auxren. Click connect and the device + will be available as MIDI device in all your audio software like Garageband. + + There are a few ways to connect using an iOS device. One way to to open + up Garageband. Click on the wrench icon in the upper right and choose 'Advanced' + Towards the bottom of advanced, you will see 'Bluetooth MIDI devices'. + You should see your Arduino 101 advertising in the list. Connect to + your device and it should be available to all other iOS MIDI apps you have. + + To send data, you use the following line: char.setValue(d, n); where char is + the BLE characteristic (in our case, midiCha), d is the data, and n is the + number of bytes of data. + The first 2 bytes of data are the header byte and timestamp byte. If you want, + you can figure out the timestamping scheme, but I just left it with a generic value + since I haven't worked on anything timeing sensitive yet (like a sequencer). + The third, fourth, and fifth bytes are standard MIDI bytes. You can send more bytes + if you would like as long as it is complies to the standard MIDI spec. + + The MIT License (MIT) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ +#include + +#define TXRX_BUF_LEN 20 //max number of bytes +#define RX_BUF_LEN 20 //max number of bytes +uint8_t rx_buf[RX_BUF_LEN]; +int rx_buf_num, rx_state = 0; +uint8_t rx_temp_buf[20]; +uint8_t outBufMidi[128]; + +//Buffer to hold 5 bytes of MIDI data. Note the timestamp is forced +uint8_t midiData[] = {0x80, 0x80, 0x00, 0x00, 0x00}; + +//Loads up buffer with values for note On +void noteOn(char chan, char note, char vel) //channel 1 +{ + midiData[2] = 0x90 + chan; + midiData[3] = note; + midiData[4] = vel; +} + +//Loads up buffer with values for note Off +void noteOff(char chan, char note) //channel 1 +{ + midiData[2] = 0x80 + chan; + midiData[3] = note; + midiData[4] = 0; +} + +BLEPeripheral midiDevice; // create peripheral instance + +BLEService midiSvc("03B80E5A-EDE8-4B33-A751-6CE34EC4C700"); // create service + +// create switch characteristic and allow remote device to read and write +BLECharacteristic midiChar("7772E5DB-3868-4112-A1A9-F2669D106BF3", BLEWrite | BLEWriteWithoutResponse | BLENotify | BLERead, 5); + +void setup() { + Serial.begin(9600); + + BLESetup(); + Serial.println(("Bluetooth device active, waiting for connections...")); +} + +void BLESetup() +{ + // set the local name peripheral advertises + midiDevice.setLocalName("Auxren"); + midiDevice.setDeviceName("Auxren"); + + // set the UUID for the service this peripheral advertises + midiDevice.setAdvertisedServiceUuid(midiSvc.uuid()); + + // add service and characteristic + midiDevice.addAttribute(midiSvc); + midiDevice.addAttribute(midiChar); + + // assign event handlers for connected, disconnected to peripheral + midiDevice.setEventHandler(BLEConnected, midiDeviceConnectHandler); + midiDevice.setEventHandler(BLEDisconnected, midiDeviceDisconnectHandler); + + // assign event handlers for characteristic + midiChar.setEventHandler(BLEWritten, midiCharacteristicWritten); + // set an initial value for the characteristic + midiChar.setValue(midiData, 5); + + // advertise the service + midiDevice.begin(); +} + +void loop() { + + /*Simple randome note player to test MIDI output + Plays random note every 400ms + */ + int note = random(0, 127); + //readMIDI(); + noteOn(0, note, 127); //loads up midiData buffer + midiChar.setValue(midiData, 5);//midiData); //posts 5 bytes + delay(200); + noteOff(0, note); + midiChar.setValue(midiData, 5);//midiData); //posts 5 bytes + delay(200); +} + + +void midiDeviceConnectHandler(BLECentral& central) { + // central connected event handler + Serial.print("Connected event, central: "); + Serial.println(central.address()); +} + +void midiDeviceDisconnectHandler(BLECentral& central) { + // central disconnected event handler + Serial.print("Disconnected event, central: "); + Serial.println(central.address()); +} + +void midiCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic) { + // central wrote new value to characteristic, update LED + Serial.print("Characteristic event, written: "); +} From de0650c15a0d44284440e4c4ba1943639b73da4f Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Tue, 28 Jun 2016 15:21:32 -0700 Subject: [PATCH 061/222] Add -std=gnu11 to compiler.c.flags in platform.txt Related to issue #221 --- platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index 5da7aad6..fcf1d336 100644 --- a/platform.txt +++ b/platform.txt @@ -14,7 +14,7 @@ compiler.prefix=arc-elf32 compiler.path={runtime.tools.arc-elf32.path}/bin/ compiler.c.cmd=arc-elf32-gcc -compiler.c.flags=-c -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ +compiler.c.flags=-c -std=gnu11 -mcpu=quarkse_em -mlittle-endian -g -Os -Wall -fno-reorder-functions -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-defer-pop -Wno-unused-but-set-variable -Wno-main -ffreestanding -fno-stack-protector -mno-sdata -ffunction-sections -fdata-sections -fsigned-char -MMD -D__ARDUINO_ARC__ compiler.c.elf.cmd=arc-elf32-gcc compiler.c.elf.flags=-nostartfiles -nodefaultlibs -nostdlib -static -Wl,-X -Wl,-N -Wl,-mcpu=quarkse_em -Wl,-marcelf -Wl,--gc-sections compiler.S.flags=-c -g -x assembler-with-cpp From 8682149177559757a57ae0b2ad6639dcf97e31b1 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Fri, 24 Jun 2016 14:33:45 -0700 Subject: [PATCH 062/222] reduce i2c delays -reduce i2c delays to increase performace without changing the timeout threshold --- cores/arduino/i2c.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cores/arduino/i2c.c b/cores/arduino/i2c.c index 9e6dc4b2..22896dab 100644 --- a/cores/arduino/i2c.c +++ b/cores/arduino/i2c.c @@ -49,7 +49,7 @@ static void ss_i2c_err(uint32_t dev_id) } static int wait_rx_or_err(bool no_stop){ - uint64_t timeout = TIMEOUT_MS; + uint64_t timeout = TIMEOUT_MS * 20; while(timeout--) { if (i2c_err_detect) { if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) @@ -70,7 +70,7 @@ static int wait_rx_or_err(bool no_stop){ return I2C_OK; } } - delay(1); + delayMicroseconds(50); } if (!no_stop) return I2C_TIMEOUT; @@ -79,7 +79,7 @@ static int wait_rx_or_err(bool no_stop){ } static int wait_tx_or_err(bool no_stop){ - uint64_t timeout = TIMEOUT_MS; + uint64_t timeout = TIMEOUT_MS * 20; while(timeout--) { if (i2c_err_detect) { if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) @@ -100,7 +100,7 @@ static int wait_tx_or_err(bool no_stop){ return I2C_OK; } } - delay(1); + delayMicroseconds(50); } if (!no_stop) return I2C_TIMEOUT; @@ -109,7 +109,7 @@ static int wait_tx_or_err(bool no_stop){ } static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ - uint64_t timeout = TIMEOUT_MS; + uint64_t timeout = TIMEOUT_MS * 20; int ret = 0; while(timeout--) { ret = ss_i2c_status(controller_id, no_stop); @@ -117,7 +117,7 @@ static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ return I2C_OK; } if (ret == I2C_BUSY) { - delay(1); + delayMicroseconds(50); } } return I2C_TIMEOUT - ret; From 9be7604bec5f080683a236cbabfe0d70b174ac13 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Wed, 20 Apr 2016 14:52:22 -0700 Subject: [PATCH 063/222] I2C - add functionality to change i2c clock speed -adds functionality to change clock speed -clock speed is set/changed when Wire.begin() is called -default is standard mode -use Wire.begin() for standard speed (100k) -use Wire.begin(I2C_SPEED_FAST) for full speed (400k) -use Wire.setClock(I2C_SPEED_FAST) for full speed (400k) --- cores/arduino/i2c.c | 46 +++++++++++++++++++++++++++++++------ cores/arduino/i2c.h | 1 + libraries/Wire/src/Wire.cpp | 18 +++++++++++++++ libraries/Wire/src/Wire.h | 6 ++++- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/cores/arduino/i2c.c b/cores/arduino/i2c.c index 22896dab..164a7562 100644 --- a/cores/arduino/i2c.c +++ b/cores/arduino/i2c.c @@ -49,7 +49,7 @@ static void ss_i2c_err(uint32_t dev_id) } static int wait_rx_or_err(bool no_stop){ - uint64_t timeout = TIMEOUT_MS * 20; + uint64_t timeout = TIMEOUT_MS * 200; while(timeout--) { if (i2c_err_detect) { if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) @@ -70,7 +70,7 @@ static int wait_rx_or_err(bool no_stop){ return I2C_OK; } } - delayMicroseconds(50); + delayMicroseconds(10); } if (!no_stop) return I2C_TIMEOUT; @@ -79,7 +79,7 @@ static int wait_rx_or_err(bool no_stop){ } static int wait_tx_or_err(bool no_stop){ - uint64_t timeout = TIMEOUT_MS * 20; + uint64_t timeout = TIMEOUT_MS * 200; while(timeout--) { if (i2c_err_detect) { if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) @@ -100,7 +100,7 @@ static int wait_tx_or_err(bool no_stop){ return I2C_OK; } } - delayMicroseconds(50); + delayMicroseconds(10); } if (!no_stop) return I2C_TIMEOUT; @@ -109,7 +109,7 @@ static int wait_tx_or_err(bool no_stop){ } static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ - uint64_t timeout = TIMEOUT_MS * 20; + uint64_t timeout = TIMEOUT_MS * 200; int ret = 0; while(timeout--) { ret = ss_i2c_status(controller_id, no_stop); @@ -117,7 +117,7 @@ static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ return I2C_OK; } if (ret == I2C_BUSY) { - delayMicroseconds(50); + delayMicroseconds(10); } } return I2C_TIMEOUT - ret; @@ -128,7 +128,7 @@ int i2c_openadapter(void) { int ret; - SET_PIN_MODE(24, I2C_MUX_MODE); // Rdx SOC PIN (Arduino header pin 18) + SET_PIN_MODE(24, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) SET_PIN_PULLUP(24, 1); @@ -156,6 +156,38 @@ int i2c_openadapter(void) return ret; } +int i2c_openadapter_speed(int i2c_speed) +{ + int ret; + + SET_PIN_MODE(24, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) + SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) + + SET_PIN_PULLUP(24, 1); + SET_PIN_PULLUP(25, 1); + + i2c_cfg_data_t i2c_cfg; + memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); + + i2c_cfg.speed = i2c_speed; + i2c_cfg.addressing_mode = I2C_7_Bit; + i2c_cfg.mode_type = I2C_MASTER; + i2c_cfg.cb_tx = ss_i2c_tx; + i2c_cfg.cb_rx = ss_i2c_rx; + i2c_cfg.cb_err = ss_i2c_err; + + i2c_tx_complete = 0; + i2c_rx_complete = 0; + i2c_err_detect = 0; + + ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg); + ss_i2c_clock_enable(I2C_SENSING_0); + ret = wait_dev_ready(I2C_SENSING_0, false); + + return ret; +} + + void i2c_setslave(uint8_t addr) { i2c_slave = addr; diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index 684b54e5..f73906fa 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -38,6 +38,7 @@ extern "C"{ #define I2C_ABRT_TXDATA_NOACK (1 << 3) int i2c_openadapter(void); +int i2c_openadapter_speed(int); void i2c_setslave(uint8_t addr); int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop); int i2c_readbytes(uint8_t *buf, int length, bool no_stop); diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 616e613e..b2b557f6 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -41,6 +41,24 @@ void TwoWire::begin(void) init_status = i2c_openadapter(); } +void TwoWire::begin(int i2c_speed) +{ + init_status = i2c_openadapter_speed(i2c_speed); +} + +void TwoWire::setClock(long speed) +{ + if(speed == 400000L) { + init_status = i2c_openadapter_speed(I2C_SPEED_FAST); + } else if(speed == 100000L) { + init_status = i2c_openadapter_speed(I2C_SPEED_SLOW); + } else if(speed == I2C_SPEED_FAST) { + init_status = i2c_openadapter_speed(I2C_SPEED_FAST); + }else { + init_status = i2c_openadapter(); + } +} + uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { int ret; diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index f055bb17..f1488f41 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -24,12 +24,16 @@ #include "Stream.h" #include "variant.h" -#define BUFFER_LENGTH 32 +#define BUFFER_LENGTH 32 +#define I2C_SPEED_SLOW 1 +#define I2C_SPEED_FAST 2 class TwoWire : public Stream { public: TwoWire(void); void begin(); + void begin(int); + void setClock(long speed); void beginTransmission(uint8_t); void beginTransmission(int); uint8_t endTransmission(void); From 019bb8fcecc1c79d78bd58f18f1b4521e73fad35 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Fri, 24 Jun 2016 14:58:48 -0700 Subject: [PATCH 064/222] update libarc32 -update libarc32 binary --- variants/arduino_101/libarc32drv_arduino101.a | Bin 431040 -> 431312 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index 1228a153c301ec688e2d61b8eb9e648378c706c4..c7e60d8ae65766a0241c1e77c6dc01dd110b940b 100644 GIT binary patch delta 53606 zcmcGX2Y3}l+xK_&>`4LAXd!_>3J_{SLhnUt=v7o&q=w!>1Wo_}QK|6prC-DAOulSLB9Wg&V3+0ui*2&*Z1wkVSanhJ@=HIowl=^eb2@odp>qy zv3ynH1IMDo%ARVLRsJ5oW^F91V~_v$zilsDR^aCez&%{$RI={-YrV=+|C`^2?v}#O z!~fK-ZTJ1zQBPR^<5z#KW&h`I)k22FVmS{+yr6W=ZcdnYX!u7_StI-Q z9`o4nzPS$QogL!cRisYoyUkI2yr2F5*Qi#_v{Th;)lTcG%d^ovggg?QhJ4R+|Qr)Ar* zdR?|%B)E3Pw3I3-X}a-aDj{F$pb^9Rr~bW$cU19JIlW3;R?&C0{x+J>5PwEf`s$8P z*@eBmN_GpWky52<<Ov7D17Te`w4Se6xqpHslHf^2VkVxnh)ZCMpX)Ek^G zoCU5e{4H|YNH`YULbwjNop3pDSK-~@zQXIkgM{H&bj)TTTe?ik@1gq|wA2<{x=v2dRg&V~D-a9g-1 zgl8aCCxst}i^F?6X`ULJGq3c!N_FveE!$pQ^=>XZL7nu*CAU}gyuM0o5_)Cs5h)!vioDVWi9ot?@-9wrd(mw#G6?z$-OPavZ{I0ptq`Aq?+j64!wop zmUYCN+aXDv_TIwzx_p+k(|e{&A#c6%k^fjnYo=8-b<}pEb5@k!7aTkg>9(zD-psW7 zRnnX{(+d7$9m^j&w*TnS<3^5UC3{(2_wKKH%6qNan|CT&&fe;?T;an|Os0+%qU-Hc zJJGWV1!?LSMB~Axj)7N#O&tSw2RA}c2RsCcHgyclyUf%v@MB<8$H2v*Z|WF01Z?UU z_&4Z0DR#aGZ^A|UsdiLMI&|Kq9M^%zQT!O!+upc3Nou6Gah+(pi0ys2PKw=4d7rA2 z2-)^J(Xme<9Mj;0nqbzmWQ2q6S9MZUb8lE(6R>REl(IXZ`yhT!e!uP*GIV)AWD6tQ zq`E0FYalv85$Y?C&&7LycYodJGGD{@x=20-7jpRx)rYK@aCXkEy1{m<`3M}y(;71G z9~^t|b5Or{9K$b={#-KZ6ptb>9Y|~4oVE>;U22tgT;ulYIq$*7SJXc5D@`UqQu%@Q zYOZ$*{=eis`anfB1Xa7RH>_!dTI`K$n(S_iqIuU;?H)}d-Gz~(Cf-p^lib}wAM2e_ zK}qU@cMlX77O||cI&+tuq$+vCnkBn$qOz|smAg%|f3DnBtEAU54RDv7=bLr3@7Jn& zJ4`M1PiTL0KIOYju$sMggY01p-U!zh zWn?Z;b)|bHxr=(rLzXPEKXJh-3BM0EHxDjmJaig~oGn%};l1Ea!au`(NH`JlUc%7` zJ484i-f~ccePtz1$($ZWN?nFXt}njzrj4ov_m`Ty0ER zjq25_q>M=QPf`3MfxP_Ju|ay(s_E6dQALy0^_(fYOUM1s%B1&CRJFWcO^LWqwN1?F z`stG{olw$UD5vq4uiM@_U%h|NTFlDn{<_LN{S#)?3LP%l=z_UJ|8;V04dgAMc*a6O3kCPheRAEQ;A_u!A6V@@Kub&>2qzm!2XNl&}dB4#7P?xX}=3y*zwd>37bj%f@;&dODkQE}b2^aX6ee^&&cl^%*)J>$C_sr}Z>Cm-KNuH*`XzYHvGL z^yo;{PDSedI8`NdR1}rsPMA$<(z>ViH~NF}>Zx3#Q-I*Y<;4O>z;iI`kb6UXLnKFMRWGt=}vNbJ(Uq2`vz*c=|z$)t0XdGhB4regS>Aq zOYwBT4NwPF$bo1oR2vI#1-BHwieM;Kqf-?8uy8oS_7-L%GE}$+lmkM6n# zY0D7F)6its#!wYtznkzx$a@I0DS1>_!`dKWA9%R%Id9t)NuEnMV~T0*0pyee8S+<% zk;5x;F03sR9u0Sma0#S;lW-bh-zxkOV%Z@)2mGq=LfCv$xGds&Td}i61lOT-SUfnx zH&bKC-$DeOj8LZ<0&oUT{u72y3(tbicf!9S5kCpP0y%pN>T`t0;wO&?Mk^$oNEw!uv5atc@3d9XVc9rqDUx;G&8sG; zC%kd1KMiBK)I;hSYMWQBiH<#nl6a63w8lIJh;K%SH+@Ztdc>Q#COYN=Wc~$uBw5xJ znAjmoQ@o4T^j1%MbD@&}*+^uLI_#~-krB-lZ^GInwK%8Q+JQkf8RDyTUhR$lQH)>;a%##Rpo|@9{ z{ve^IcpJlaGYTSvy$)v4Ji^GZ8RQ+cF;(^OuHRT!t@EDR811PYj3FF*BlxBv2gQUd z!$K|L@sRftJ_BoGgg2q+RtpzLdUgr#N4dQ#d=o|dgYZ7Eh0Q90@9yxm_r ztUp_-BLA`1N~@KQIXLGzbA8pdS`~edzDoB?S26eKjLfp9KAo;YeflMpec#?j&sTP= zFD*w^w6!PHjx9T;_rQ@^BYM|*G_7~5&YkWv_pYTseicK37hX}{=z?#lBEH{VRr8fz z_nNvp5%PuaRu2cqwnj0Ut}6k32#U^hUEudDJ$;`_^!y8#y9SEVfvhChOnbmrakZO@ zoOfeu;bO37X5G-K3w<-|244pE5uHfzK;aE=hYRP2&B?-F!saxz5GLY>QAg*B2WJdg z_z;w6fQhS(z-HDBegZnCg9C2>?-!jl(0^C>Pv{>NuBhkiS4nnPmws`-D(XpsSFU)S zLYe$3JQi{`;Eb*r24467WM(`K)v_mSDp?5)z?k9)Tc)IQ0^;>%iZtOTe{h35p8(uZ35< z8ElON8wj0^fnbR3O_4td`DY?mxOQjB(yd+;`81T_&*WIY{e0|!Jlg?tTK8JHs zccgPcucvce=fZJYZ`M-zb!2@t;LgNNqx&oC+g4w_ z91=SPH7L*rW}|il`oQyUJ*l}$3_FOr8t4N@>*t%Rx@lYu?1y^73c~e{Ea5Fs9WNY$ zx-vz0sxHz(C3yzGd%cL}BG|LSZ2Ptg-+)eza8u}T&5zMEM9SV0W<5VBTouv0FU)cC zapB6)|5TXsr&H)ReJxa6n1#FjXYp8~&$Pg;Hy+`NLx=Ia58H{tJ#|z|G;Lq#@-0zG z3hK5kRox8sqANuq864IlAMEHlu zUP9&r9mN}t4sQkjScKq43jgodN%FhBr@}VDlxHo&=f7(5qXiRJBqcZKdj# zxd;u@j2jJq6HjYbkz%g9lE>=G87eyC3#fWT^eb2kqsg+K6TX39tP>2j42kz^PkphSRAQ8Br0e%Z&id(jbVlk^bSCS{{op*Qr_kA^kJ34*T)9B|+XJUqC>u6dC973>2^`yLt@jRA zWy9htVjhdas)<4>?M>)d+`SNMjW2qS;~8VujuA=!)aq7COZP?;EuXWaV;R@q&qf;D zZzAILbRDHTy{s;JQy+}K*MmT`pWd3?BJ_rvb|LTWs`Ey5*4!%yohq#Ej(7?$N6DB@6JbBlsN-mGmMvYXgfNGYD<62rq&qd)V^v7Zj!@ZF_DFs4j7s?rzodX)EuOS5EaT_{ z-(pt+q1susiD0iTpc|A8s;%p;QUiRCom0OnXKe7Kx_ZKQYJ4mo;FK^eWAH3;yq{-h zTRQjxTGgj*UGaiSXt-c0@>kFAxhNal$j{G^8~fQyZsO;~{L2~N!Nk$OS>2_01$72Pz~5O6J5d|&qaHo4>bvftM<(RTSt zP;~WzXTc%;AG7R=Joi{;h-|03I6f$BJksf5Mo5tE*C`S`{v%A4F?s`}G8}IISz1s)8yWI`l z+<2o2LDo3eHP(%PG=0=tO09*sSlZJ}4mzpi2QjZJ7 z2NV*#BEguBvVq8>fhhs_FD0J4!H^|ZOn;Vs4rJ*7tgBV$?_}xcK$c4M>p$L7zqUaT z9vnzn>V_#BVv;#8VrnO`DSm3zK#XNdi;pqHYf;8nLWzi}vPPkpDd%KXY##Je#TB2q z#0SpH@yQ7mZdt#17@abz!eDdmPeFw{DQE)?wd%s16jb0fW&D8@RQit;RQ{V3R8`0S zF$MMinu4}>Qn1COfRj;w8MIY{JiL=}1O#l-@}39E^S|}~PklzlqoOI}b|#0aXC;a- zzF8{yw<;S!2a{pd>#v30Umb#xcxo_l3I0OoY4TqRev0DsyOh81;foOub~vCurm7D1 z6tGK~%=)j(1O8HB`SWS5TD2YnOMfmO@V8))2G0LlDi4@s!uyW@UvvF{3go&9m3YNd zRkxs@RF{z3v8k%7>nGJYRdrESQdMW&>xwGnX?f=o#Up@P)f^4BKkkv=-eV4sZRVf@speRmS^#D65>i91I9x6Z6P6}QajzLuJO z$B_RzKY1rj{_{C^&aE`wbH@--`ViA9T2&dpYQnhPE^=C9Xyh6VoY|r<^vqoaHW~$S znbU_bs3>f)A@N(l3lNz6Rc0TM&)njEK_#~8c?6w9DzYWcBMB+bMl6rOj%V|huM+I# z8%?XmlAXv(W~5eiN<%7`F!_EC)oGVqrS!j&RfL|iMOF2EoU8V@ij6I4a+bK3$~?mG zOs@mBZ$JODO2A|M+-+E!i7euj(jA_5C+Ok7s35SS| z`SceVN&NUQsLb%s*5qwMB3K z16}(D-SMW1|NB9It$$o)@jrs7c?(lNOp+h@6Jwb3Q&OJD9@sj~H6X=>z1n|b$o8{7 z@uw=|Sz@c!tx_G^wRGwLN4auUM#w~*Ju~%noLyHLc8H~vuj>ES4X~thgPq_4Zx77zrey~^GbF~P|Nj^Mx zsp-!=u?Q!z4nBu(UOyPgzt$UJJt>!-G9v3%+X`@>JYn4@R*T9dJpYCTwe&W zwO$r#KYn-0#4YK*dim@EDw^YfCgILn)ik`oJXiDZ$ock4$6ls;=eNfdV=rJlGr}Y1 zIqkv=uXHyJD{fEsUCM8dw6U9{XSjVEwW4Q)Jwk2q9gVO(u1r2}h)OfH)v7|~oC`;t zJn|-a;QJliz*q~KmJGE;|U|>zP4Ot#)b|9k_ z;K5;6VCU7FWHb7-tbJrmwRjxB&yn8f13j~_T`G1O?n7!i<*^4kNEYb84V2zn*iQ7E zL)EJx{$3=uzOW0Uk*2~m!L5bkV2`6y+WQFlW^M_#AnzmcnUD_@J_y&$GodpYV}{8h z=N|THY=&uQN~k=f0+&OAv?%q4(pKRsFuFsy8FXG1t^^%Z9tfL&guX5E#(H-VJIQ|2 z(O(s@i+Z?3eLfHbd`b9s@HOFQ(aPQsUJp~Zg$p8i1ra@y+5k}(6RwM>`CyOoj*yoY z{vLMB3>fkg&_QLw773ixLm|}^r8Drz5IzzryFs8c7HoEdfXBg*c~b#AAM%l+&kbth zh10=&)=&HIAkhnj9|12F{?bOzvsz9#f-q~12=FSD4v4%5 z2(xS+7v2e*vxScb*+|;Q2@%rT55XUy#u^}(Ntjt>=(Z3T4}LvD65!{#v5m1`b)m?a&I!BNDFj7AHP5rAC` z_ZE`h11E^i<8J>(D~63kf*MmU+*P<1CnGM701Aal`=142N%80n zk0c5365JG#bL(JLk>7&bK;&OR{(#8C5UJV7jR^RrR%ekXAOpQbpIhboihLw{^x@*c zeqfq-u=dUs`BBIhiJT>|k&K+xLC$jW@IKKmhwJ^m$Y(+4Ymsw0elCyv2ASj5!HpCN8siGMg$KE zH-LPQ@Dg0Uslvrk)C+{KL7zvU$%mSyUrw+~UmY=n`o!T zFrHf?B4a7Qm{{Sfon(KluwD^U#!hX;oT@ZKdqCcFYXBM;9OX3{y3rasy1Zw7DC zi^|y1#+(@-i@BUUCidjv{dr6r&ch!FZ_&8{a~DO#)R~Q8FwNAN@v|`Z{{~WI<9-Zq zknk4Wu`Gu5oOCCNh-^mGFu_JERpewdx`uotxQ@ul4TPDL=E6)$hA<0+Eh(et(Nnks zxStu;!-FS-@&q28hsO)k(3CvPnKq4Xf!vJDB?7Yz0?Y)h5gqadVJ2?d9mZ|7Lrxfh z8NMSh`3;dX0ygc8jLTrhg`0vu&%@k*Nu4&3pUuM;gqg`-^6>9u4+3<7M=0(w1}29I zGu7NSNI6qoOqhvd-$8i;aHTvt>^mr*1$o0fa&`rQuA-ALM-!fh@|^H#U7#sv9}x&J zCXddfJUlgzKKqV<{^C43EA#N$Jo@ZYpwDIv!)x&f2b=wcvDk?L-j^rvyLp%!e*y_* z9~6lAjBq5vUdY3jgqh=?^6;+?;tv>NhZN|r!h}m90C$H{PBxPf=}*{E1@u#d3qq%Q z9Hh4zrNMD!@b9GhzpFEJ@Z@P*Zq}_YF(6Yr5?c)%2EXc023`{kfXW zt*6bZ!|A7&(3z~y(OImk*MPH4&!lrepQvG1#7-nt6W<~@sms)~lhs1qmd;Q;j!qZ7 zn$ARhkj^rFna&fsNG&_r%|`e+-MALQF4X-Y!5fV8=!^Vmw|-3@WUDu4PAH zYpT08d=Kc#bUxEv>BQ?PaNO~zjXju-Li)|xb|hY&JW4TlSBLP^Ai6*uJJOu4*9mp( zBzMyqG~Nnm#}(4U>)2)8mod~itCvHBT<@ua;Kxz=%lKgheG|d$O6_!bT_|Q@T=%3A zx2cP`Zs?wMp_~ip7QP>%S5Z1qZ-+EUCt$>j=QMTgME9DC7|Ux_57D0nVvjHP*w(8D z)3rM4cJ*NTHB^v~%tl%}Bt@^G=mOT@t5H-)mmcz8Y!FIIOUGU=zFg8pPaC2ZL{-c# za4{@9_-a(>=T?R6po@5?e<*fA@5xuiN`1_EASlvNjgktuDwMVgg_kZ6)nRPD(%BK# zKFf6^G2GQCsijr%v8JPrl%7tRg5SvYrDxmoMm`sB*+a@^k7OOnzy_oe&Fb}=y{_6- zr$w^r*mN@+C$_GN49m=XuHoMTG@G6mQMn;E^FZkfP6|E|kZNy~Sc&ua94}UePb=mA^ zdTnm}>E=?cD#T;?a&x1E>2^hvmqu1{mZ)2mMwQuKX=cU8zKL&QF-Xa4e;+2_{|J-s zq8>U-T~I&i`elRK>9=B)TR%5kjdI4iCiT~GBe3VPKW^C)`B`|bS>$*>&u*``jli?C zP5RgfmDpebH=@<^do5}YZsg}@$c_E%B{%W&V)6riUeaDy8L8@ot(Xg0cfV}4o-mSI zifERTDa5{sK}K3`hc26c%e9$rN4TARU^ds5s-)IJ5@w$0R~n)}8>!+8aK0XCBo7SH z&M1|XH5n2fb?{TG_{g*HlOihO6)+9f9kDr!7C+Nwsou13#8}`;uRn&~Ll9hbz`zMk z@5lARQL2$=HP3cYvg!~ti<`8prY4Vq{7|+wCy5>KQ>!-IiRa{B<2fCOrzDfY zgNat(7cMHNrpKhLNCG6o0vhH;;W*V%RSD$HKcTkNHL7q3s#f`PcI~e*UJt~GMha`@ zNclM!7At=(G5>SzQqApn-=r~Wh0RCMp?dc(*bQH9JX+x%<5UqnvJzwi#$$W8dDgsR z0$ve+X}gnOS83uH-%ac&I+s7H=w4$#PZlQ+#`; zq+UEhc|utcc zN@lqFO`mbSP3p{6sg+ZQw3?B=r&ZO~u6`-55-C}B5a*z7M2eeYwNf)G4@ey}WZ=3s zGb^Xgcw=qrHf^)~(B9Y9&ifSkkWyI{2c!+E+P3vxJ3L^d9ITuS__$v1WDI;_U}~!C zBP(OWT_xyT^DUU9l)Cd6c){bUt1~Qf%n)5;vZ`>;2hMywq2gp!z}IK8>Z+^edqehW@Gswia`qE4S|{g72iYCRj`WTT~Hh=Bz@qf;Kv6RJYLj~ z%~0)Qo1nDK6Iu+hAIAa!I%SLBc5pd*X`P_Nuq@o_=(~-qqKL|>3@K6*_ zR1shePO`)!3XzQyehPu731flEnkVc9FBj(Qk58d!hbu397)0g+%RR!2pu^Q`%K0GZ zgz!t8D4vlM4{~r>m@CnIfX4uzz~#L}&Ol%$ko+L@r~5&2NaJ-6j#Cr%vXDDZNbdD|UE{{=Z8_yy#p$VhZQB(4k@w*-&IBEJYWk46#p z8*q2Z!Q5kR7HJT60OSMxa*wGrLnZKwaLvLD0(3`!sUqilCo_bnBJdn?J^&8000aG5 z(0^8RR>0j!hMaZaRnbp}{=1@64Sdvv>mPWYc3uK}j{rZ25)J(e-d%oSSoG7DZ+d~rW)Dww(`gn31U4lYbDTM!AjSIO7Q3kkNy&Xz1Uch4}$!$ zJaWEuNPRvecv|F%(BDXgQBF{vC*#2%5A*mG`maF$9noRNj)IHO&>49ATLP3sfb+hC zPvU(K4`+;*@#8fno3;VWCepk!0A^EYKAr^b0_LYUs822=+yfjd+y`uSTR`Uk*t8ko zcyOBN&?X+EwKIlzQcpbCfIg6iTL?2U))z)R5zI$w*guI^pLa-IWnBRbRVj#j($_IW|kdewZ@z06!uK}hR0vKbv?CQg=`_p>i%fhy(F zSG~&7^`223)CXpAxg$T`%W0{1KBJP|%-745E-e6I7p=Syc0k3bXH*+`AswnaQaTsX z4o13=(usOKr6(b6#A$C5Cd#>#lt3N(RUgm746w>#yb!bsWl&BxTa3@_6vB+=O@1R& zXTwMLnHl8h#fw#G%#wF6R>|reeTL3l9l8XD3ZWu*Hxt*EOAz5D{Sc)?AkFWeU@oKh zfPS9h@ex>K)hCu9mNeW9{x?7)@p%L6EKFF6SC5L7))`AxSxnbQ;Z(h*m(zJt?_Y`? zhsUz)|K>XgHLCc(gK)uDd9Zz|NbqW8)wa&x>jOTcTG>tS_ZreaeFnCu4$H7Zb^Qsh zg8IwdPP*Pyq6;gxN!$6<&$3-wR(w2CfPx zg`lJPMNYghbW@mX-8OGk7(Ig$3K9MW{^7!n5Lr=SZXr$({uL!rRk$@G<`|N8-a%N7 z9mxD-3WiyDzK0X`PG*<|{szT0QIysrg4x1d-1_0=cA`3=r!2QqJ$(PRENs(OS#Txc zCs1JN!rhV4TEdaY10StZ|1;>D0S~wpxUeBs73PxeDdA)oHG?wP;a7gY z7dboqTf*NVaV{i;aRosqRQM5Y8^Y!_ z0*445gnn(2$HQ$XJPoy}nQ#lZW^m_0fOMR65|7W3QZu@P{5oVKMScNB&43Pa=615k z3nOAPpo6?3B3LSNE*Y&7-U+!G+(D;0^q&_w{XK8W$vNcgZDHtJ?+K@(xK0XlF#nBk z1QKykxB^?a4Q`tHBZQ(v_YR*Wk(PD11(Jl z(R~uSW?TpFl8|MI{3Xaa17SSHVcYDB0~baC@*545XF+FyZ~~YsFO>5s;&Z}(>de)+ z4Hm=ubrH41#os5q8GJ~Xo%jdBFQOdHNDty?(779dijv%Ml;< zr>#YT%>xg_bx+cc2JfJbH`woKRhI0~*+?y72}(2Y+}0 z!xb23NKX8}6h4oVHebeqycJBi@uN;%WQyyrUrUD1UH6(_da?L(ie=wFM(=Pq}Z(rsR}%Y`n6 zs0uWb^t9@DujKUfpkn&9>JEo@2Vca)n`64jOK?8Z{a>=*#dka^@31F?E~|~Z9Z5>^ z?tHnB-nYZ9hQZ#?JD_)1H`|G4J?r(Tofx-t*GqQdk;hsr$Y$yNK=UbfJSN$RCm(He z*e*LcY+WPETF3<87q8b3#;bHybWi&9C<_TPQyM<8=3Vv4p<;A8_L zHN!;kP_P*qf*XL%a1hLQugwq;%p*q(HG&*NJ!6L-f#dcy+RW06dZLqAt@p#hYft)G zPdf#q6MNas!wMo<4u8-*smJxQKUII~w!P7cwzTzt-k1mtKqfd)qs9otH(r=S0khWv z@;%`BB4-|!3nxO~Y>|M@n~<}n(aw+1|5})PF|G^$1bsK+qt3%ff2kl2U2!rGfvboI z*BqM*Uxxfa;g=!jlW6L505MNE2gY9$ei25$7XA***%|e@FM}UcCzl5EogQ*$%Qvf! zJzmx4Gp#@`Vy=qxA{!`|o?{Og-4c&4$+DiIe6=679|%%WdfE;PCcEmsa{ft`GYWe@fz*S%McU_}HgEJASZ8`U9t1*S{ zc#jGAfA!a0@=oj5p0^9#!xks=I{$Zen4a)&*FoRbk6c;m9^Wd_2?_2roqWPo`(CXw z+x!eY_zycQc-+{mp=0ppJbIsSRpH;@DWpF<;nH_o>)hAf$-Y&exEk59RdEGOYaNb0 zABAEj_ux57|MHnD#r$EG#?ayS)bgV(Xf6x~m)tL}i>k#{MC!Z?8)$|MbCGMP@ObbT zVeUYjD109BnZj(F<_a%_j@PuPFj@j0E5suk9vg+Zcz;ls)3W2jo57z7D0A<2|MR%uh!|Fbhhd3=Ufx; z0iQDGadu3PqhslV=Uo+5f1P_Ch9~MG-?@_AH*hN^>&8GCHckG{73uDW8*i>zI2>p@ z`nm611;SQgiw^r}4704FW(egz3sHXa$3McZB0vY^H5R^6W*F57RjU)%_o}DXNV_|P z0^NT^6(3)z3>8 zZOf;hKKy})KKWwXqct|SEh^|JR5Nqifq4igumzn~!tA@d3BQAexu-Nrxv?Xx;Db~FgGGhwFbW^YO~b>JNC2gOlNYBU}#I_)%Fw#v?+9E_EfPvClTQE_8b%*;RNO zgE`QtC!C9t;svCm94!RkZZ+(0s%$?X6vteifkAI;Y&x*%FMD~MlA-HA?1)bR_$KOPL z5P{8xKgi!hB7$*FJN%YfxG*>Em_;tgry}1aM7|K^o+SKoet1-nlOB4CMuFgO2l^MX z5RTQOxp?oxXrrz01h`#<-$i;K5$1Zzqr!YNmnF?mRo=H-U z3vT1$Qb$84LU=g1g0KtG)D->@Y2*Zh`oAOX9fiYD)Xw}ehrHy``q zgt=@e9`T5*wQx5W=d6V~1CUF8aF^T`Mn?#9U~5Ltknhnum!n{*YW5sMlndS~s*Lk} z;bzD;mzrtrRp@*xJO(bCAIe`tdT$DkL*+8>PC`DCX-BlwVL7o($SkMUX3&ij3eDge z%n^G(QThatEfBVm@0G$d^sF!q@l_%krJc8gUxLmD!U_rELjme=iPwch`4fbz5+Nt$ z^zjua5Zb6JBHCyr`~%`KuP?&JLy$9LwDA(sXkJ+ab87jN$Tz@UD$MlqJdnm0g;|qd z7k(Or_inJI2d+d-V}P&o1Yj*;VAi5vg?WYe)pW{PDI$bfDfo5~<*XFR!Z#tWD*PDi zHxy>XZG_7}A5Sg(?G+QzPdr#EBZXN_CJQqWPYTn}65(;sSuadG+l5(u4hpm6_$eeN zlwsLdkY@*D-Q#;XnTLAyi!d)iIO-ym7&um#fs=)AqlC=ch|pog4Moljv=&~A(&{dp z4>lhq!v>F0WJXX~|F+82LN(NlSG%I|Cs`g^?dlzq3hg#%5&|Pfu6+BIk3%bsmuDd*Y+{-{tX$JA##r7xd_f+**a#8t8Pp=q?3=G0t<#*T=rWXwg%&2TFr+at^SJ8 z5oCn^8LN+LTt#D;wQ}O$AMJ5v@z2&r*I<9hZT32T^K(}4zijJv_=t`_$B5Zz!CrZtsy*G&@WmIUHMI2+?sf1uTyOrTdb zp<0&Ew|G`r7uk%<^^k7185zyiS({NRe2p}@AVP73i=zhF95{lE~w8vQ&XfWVw)hG8DKFX=Ge09-YV${=LAKc})r>#bcIl+#9Yp9Q<9Rw0)SS zIeHqM68bou#X4a>oa=fNodSA4ozgn$Z8-IGCY_0TC!K{_y#wb1d{-V$h+a=8Ugy%O zg^#&oK6qH~K7g~4I`kl%V)~(jm=7-X@8(!`(8W(^KYtLD!fz{}v(zVmGAWEa1kaN? z;SeO3bSpZg^(Z>s^>RAcX>rIEQ?-EE`Hgbe=n^&>n_o{ZjdX~+bVy!Z{KCR zW0-H+ANC{mo#~qoA4l2|7PA92!OYweEo&KSjG4KCd+As5yHY*NQL!4MJ~$9@6L(AD zdEoZKt59dm1PwaNQR~eF4Sc~ye--MSSp`o}nnVHv-&*Aw4vMO_D7}i*Hxhmjm$ikk z8;NKqyc|s|rx}cZPeXeMvtjBhoP)>)3-b*~vnc}l=L%pb!EeSeFh^q^;pT{d+XN|p z0gcx@;gK-J$sFaML1(3K5=zUgz(U?0{Jh9Z;ToHZ>=`veVAukWvEs>k42Cf+O-$wjgS0rb^wAqmg zE{^y)D5QLWt{j2>FCL~-M8wtU>cSu4GhrC_M&UF=MD=iqIto7oHhWcJsXa=tx5$%G zIs=3+AcMn%Cm}^+gRnaItj>@D(X+F|xUMPmr zX;iGuA|F^lmyC234ZDQmd0k}3bmK_m;Wgf1BFaUz`BXR*SL|Ei6DXxC!h8ps&$gJp z#~}~K6(ny$n#|?~@HXTpUgWWe((G-3ybY>fEs;Nm>W$eW{@M{d_=N|v+X4J0B4)Lq zoSz>sZ~20ASui4Zxpa7xtElHN3ip`ElHr~dehv1_%e4qM0)>8EjXD zVP>$VFf-Uxm^W=l;gQH-FX1$}L)?5W1VeRT^fB?+jSDbSxB(LXjBs-#bgghaN@TY% zOXT0eTaa<{+yyqj(YK;-adK^cz8Os%3XB_r$b+F8F3f^tAyeK51#f1K;OdYy5_uie zg)YLu$Ty$i1(H5o7)uQPcR&$#1d@e)KK}gWAcCc$R3G`!; z@4|24LYT=SbXef#13BQ$`f@>x#p-BxAs7CT1GHzNgqWnBh?;+1k9-U6I^j^1=62y? zi1`g+E)ZZ2X!LnGKN4oKnCT$w%mJI}AovOBo9Q5!)eh4^OxFPqz_l5bC+rmA#`&;0Vvd}!BC;$Q zc#y7N7;O;i-EI-Fs+p-Eyyxg)@b<7_G!s9Fm?Sgt1M})|08LA*77@a&a25FK3FWMn zW)cWytuzxqaC=k*^Y>!FtZKbQpJh5Yk4=1G#$R?U=y~G7L@XC(z1t>?*Ly79myDP? z2ZWi>W5O+u&}JovYR773R{sc<_U6PE&`TZDf_ zg0=~7Morr#JPwzD%`x>kQ`jrK5IH{}+!A4r2nT^Z$K)gxhCUId%zU2)hWPO`Gf@UJ z0T)DvIW&K50`m8uWB%F%cq}6RU355VvtXAAT7aq-B>XVyM*%;3tOm$gLGh@Kx?fDV z5lW?`a9z~j(!v`NK?UJi(5WKKciL+RuS1UO3&$fd=DRou$D^Cb&%y1JzYYb3xi97RC3W`1|zn z7(C%X+P;r*)rnaIt4&bP0u#TEWR(6nT|X9y<#(k9Q-oMHz{&{mM)2XW2wo7Wc#kra z8IRBI1mDl#Y-MsKcoItKm%G8Q#k!`OvRH&Bj^^{h)KW5Hhxz%%Vg3LT%_nYwDd%nR zKc~+WM{B-a|5h9e5zwws!qwcv4QoDJ;J~Ex5Se*FNgg93mdd#3Cq&L(;A@fdV+UtN z&PL%!kxzpBCy}Rs&8#1Gwtx%ZcA(97!BJ6`zEZ*!r)ujk>{~a*KUDm`fd42m(sE1J zhc}blEzUJPrUeS69-0XAIXjeJYqBZ++&F*E5=){^R14OpzBHy9c zOYqlAxtgctLsj{iUa-!CUnvR%k02xX07Ow(KWAJQo@&fJxjYjjq&i2Xkb}rEE)PdW|Lu` z#}{PWyF9p)A<#NlXaWMadTlZannxQlN|HxEGP28K5*caW@ftY-{Wp*Id4h7}VFvxk z43FO_NAdG8n~|iham_nWam;`om4^o($_6S!FETD0k5OclHxCZL`1v0m+VQ0~bR7v- z&-xdGBHOuYxua@g8Cth(=Sp(#$_Q+{d9t1BuwLkP{)-oCs-{=*|LwGBB({vbBrUGeoR>O6JNXXNIw`j5q&{W_|rQ`DCf>l{|T3MHIp?)fci|7OUW zF-{5nZk+S>odp@a=mNIE>?`SPbH{Q+5{sEjj-AoivIxmvT6*tqScKqrAX7!gjR-Y_ zIh8ff)1kWxHkyi@pJQw-%r_!B3G;!;L&E*x4iv5fo#DdAah)d!MXML5&0L;=YCC782?>{Dq`)`?2vZnI6|(FTTI7v2u{knlJJ{z!PWo>SII%H)e6arn`8F}PfPAP<0A zbzv7w^WARBZ-dPe4Vb&@xjl^XC*ckg<`daT0oGy3PIP@v9L)j?R5@ff3oKwhxHStb z;ChJCEUz$*hrp z8Mchb8P@F6hWsG(8;JZ9L~m9_L?7>U;H^cRFu-6@;=4-Ygo`5pXQI@Z21DD0gLUO{ zPISzEoF1b{TC@}5T}=0ccPy{VkK)~pwE*X|bllPN%Q@p?`K?s*)&r8x!zcdxUAkm> zrzm>6>gAo@v1d`pz3~gQzr)Ee1GN{S7Q@8PrVObl2b1Pgz3?BWPnCCOs3tnI0@BK< z0LL-Z+6%4DWTUmHg44pj;^;3bIEiYKzC~?j_PS_usqeQt+LbFh(RhWbSw&|?T6x&~ z78ikb)-kifiIDTX3(7~q5_iFnTj>4c-O;|tO3pHO{qFDxbTu=`h=RvvGOsL-cgfP# z@P(T|R}<+wm*)IrW8MApY7RGgm9Gxxf_{unY5g9ZmO7>eoP|1z&MLjThBEM~KFQMyI4$h|%Fzyn!e@aP>Odt7-OZjb{7t#2+K^N#fyGp_pT6k@S7g#Z?f$A+ zt-6lLaaZuIzu@{IDEMLI-L?wfug|!C#kJy|J%H&m=I6R*+;0uPfgXR&Ra}?2hQCa4 zyrH|aZ|gPJJmnjI-4&B(5g&W7+^*PNs1vxL=Bn~}XrQ~;Cf$XCEYMxlN6iRy7wnP) z-39l?HWeG4p&#fjxFj6tE`EZ4pu3m?9w_?VpcCjW-o`CPKh`j|UGvaR!rvo7$Awoy{+aM)@L6HZH!LQQ5kH8yY=j|?P{=wrxbx&! z1gI*^{n`zMTOuG|OruVH9rlMSI*i+|*t}5`t<(N+CDmv9%-zrw)dU|F4uflUSVI09 zvT#P^4b0qax6kQ+wBBluHYvNr@~xiVSWgrs&EaZ z|NH|hxL+cwW+HoEC)~v9*<=LiDI!h)%>qB7a6^_Q@;_l}gz!Z$lVUOr_i^E$V0xM` zTQxHRg`FN?_UqJVujUng3U-#8&GGPP3Z=E;F&ZA5g}EB`g79+iPT}{#uL<`QsccG)gHMbmeC^@(QrX2)V4%K^4I(52!kYAo)Le>Ym z?L~JMm_q`FWA%7Mcn&JuAmQDZE)Nsty4fV*bGq#*bkU9A?G@1g)X{aq*Y%WBPEz<6 zn8&^*qV*yA#Zyk5GWb*1{#~btl@BL=5dS(z%`d`hbl6u;5?(7ygA>Mge7msU^9k=JXYU=YQ|{9 zXP#F=#D}V1iRy>Q|5@Q{h>guN(=-RBuL^fUA^alzKz`lpYp1A(!{-p*z|dU|4i|n2 zHq0|m$Y;WKtjL>!{C35b^VdKfT_@@%v+I$BQCw1~; zxFsI%fH@zce1MKRjnW$dUDN78v=jMxO1#VJ#;2XS_}jEopk;^U(@Re~bv%4CvJaaY zXfHx8#t44~!?T1RgnXVb|6I#r;U>7w?93Q;Kjd7rBVR=>o)_k4>2?UOL~4A(ZK1Q* zg>Sktz)=+QhvLBmaVkUkv%z}!8H`*@>6vFx2m2tr*{cb!Px1EK87DD~pU-|2>7zP> z4i|nFX)~Y7g}gLmvqk=s4*kYSEt|tw@&w~cr2ZJ?1GNYigNyzRqM+GyBsbvSP7z_L<1G9v1)FJ408JLBVfFwtLUUPk`M z>&Gs`#BE*VM<>TdML+T*OiV<~&tvw$RIEW-UnIjsGaYpWxwx&XUvYZJ%*u~x8P>4^ z>wJ9RNUa-s`xR#b(^K}UlNfsySNtZu68%>oic76fE0AA5de!NL_jvbTMN3-^acc2; z1-wmo1cL7u{z%`tihHv%E_Ek#SG01$(J8r@Nph3Ne39)2?-d@Wd*-4}@lUSg!w`}| zUd)dXqwrGSyj*8?5s%rkfmnHPa37e(nGu&%owq4R;qovGiLk@tN6HZ;j}W#d7{c%{ zuU=#P!o%!$;Gi3a`8)$I3JqO_oUt*?M`y< zX%rZa-Hdi0)*Wj97wd-URjOC_e=~NSZ+mTLesnNDK4Dvj?>o}MB(S*N+tCTS$4Kfg z!>uAZdzu~efAfJJj=cU!KiXHNvop%p!DrkxeKor|U)^(3>R*<`*sP#l|Bbt(*0b&6 zzIOkov}=K`s<_&@mpcan1`>^*xPXM*QIqdWWj;F2ZY=h^4-CEf4w{@{|y-qq%2!SbM+d=*)qq`=6%xINZ6 zL*Kg;?TdGuTRR_d=1}7^iZdX;RWZlNUunRgdlhpENuBM#qOfdO*~6Of91`qo zGw|;R@3`_iLFTWD3m|hwF?WmMpWy#xF#eL_IA9yp1b-B+i4AH3PeZy5Y6AN>eLED2 znfU-RL@6%8Kd^mS@Hw8wIZ~8ah<{`IwZL`2LzG_*8N1d9{9mI08}b3J1b>>!a6&sH z2-L%%zU=_Zvk!V&1ua3Amo;f1LNmB8L8y&gZVhR^KI%2O6LNm5co+V<2WiyENEcUi z64R6MD!vA4=edDD1eYyd`Co!|Q~VM5$%+?4KllLTb2zii5A=Wxr@#~=N6my1OXT@ufIYqJH zDi2i5^)90nbN*3|;#Y80iWM{OJjKD_v+w9BN5LzgXpJWDa&1za1YE0lB4lbq zfQfi4l-kHPaEm~ByAb~CSUFSZS>YbuOy(DP5-?}Gw#YNiHA7s*@U*Uow-|ouvo5)< z82$_dB_`$Vt0@Q%45GKUz2mi@ZSC;(K9@;UN0)a^$}FU zcHNU0N?w&oGaxlasvza^%Jvzkz^n3mo;@mOaAvbMfpTV@iMli+wprVkK)7B~N+8@s zCX!5*d1UsLH6`#MhsjZ%U6Bh&^R7qDV&N50(HzvLGcgohljKtPwX0=iDSCqM$iY%i zV)=Iv=nl7u0!#3(rz$=PB?}eL$KTzon16qtV$L!9Q1NBRa7`-pY{Q@C++$*HRu-jr zHuSU4Lq6wFj=U)#)Sm1>=E<61Jig^+p7nv{b{q%ymWQ49iZ?M2>(HTgJh%Y2A*A1r z7^U&Bqr~bM+MyWKjK>p{K|wqiplxsrcM_{(_#ttt0DozxeB0-H?)BgU2|)`HFRPSE zB&(&CK*fZLFH9_Vt_PmJ&1w)>I zTYj~l?0Ld-7t{q++ANbQ5tFO;e`}x;F}Af*TZxF;^EV@GA%6kHFpO&nLUV`W>D$}S zA`C!~&DB}bmq2jXP&{HBeTc>Kgc@?zcHda&w4T4jna)FR{>sxEtATfxcFt-8LsGzpzYxU2FzjfAC;iwQ;1T*tC)} z#U@Vnz2Rvqc{9wiABLOl^6hpdCdb|K3ThaJJIXtYEgzPbnHbkL*FC$kuWZ@A>M`4_n#caF8g~2S>2jZP&`lBnDIm=`P z9Y_AV@uR>JA4a>Xo48DMRop$kt&f;FF05ebGS{%h&6#T+Mx#8(v-6TR&y0586k5Hf zQ@CuIXWF=KvEkiA^Gq<}zQ^Yo?CgZ+=W_L?j8KW1Z-Nb%N%%v&!+6U1b^eV@&vKK~ zBv~*Yd4{3y^Fj5wj97GU-y>r#sx`|-cu$8r!8dGJy?Ukeu?_15-|z^h-ql!qm5oW3 zd!6fbJ7T2X>l8NDgsf-Z{58{B(tBh7*A9_b8}Kg`9R zX8G-$A>X$(-=22PdY2txwLJj*@9nsE4Nb0VfNgT^hv8l(Y6GH2*GF-8@Ka^ea#v_( z7~n`{bEBaQ#j(JX6wd&iqWEW^MT!@K+MWZ7=d0>*<=-joJ76=}&Azk_&dYAR11>~6 z4`U%yL5wpRVU*n@Pf1X$)6JD(Z~3TL2isBL&5FU?SSQwO0UTx{`s!N8{`31$(?RH%O({pF# zPM2~_hLLxwP0#B#v6d%I3;E=Bw6o5u&5|FQ3%ZWWnntFf3E1Y+-rrxb%>{V4kq6e9 zn0OBJ^yEEcI;`PO6t`<=Bj7KU+I1$PoaQV?lNsE9NHIg>C5q<(+t(DbjR3aI1GpEe zu}oz?fF9ei1b+c=jq;yH@xM^a#T~CIJ`4Oi*m7IP6EeKU#KtE=*7hBtV=~J5Qf1$S z>{-PZWMvJiO^4nNV?s0n*_z>;|CaqGyTJr7k2cDG23LgEhBAeqQHpN@?WmZ}Hy147=9anWq|2k|TZk=>{`HNz8v zl$S%O$H+qR>qus|kIA#8$0iez%4EBa2Fafwna(nksg-?hV!jpa5>E};4N!hBS+EJU z+$-BRnLE7^$njgI@S(zSSfzd`ABZ#?8)fyWjte62VyzriC@D| zo|TjrK-$P6k|;S$(pTbZK{8|}$$fHwBu~O#1SykTk_y>D@}!upAZsOaD~xZQ93(j} zL$+D6dmGZmOVDVR!)>i{w+)|_TbNT+l2w>pkQ*?iD7z%bLdl3W4>zXA8uGWI z&7|Ny2}!+rluYf}C8~Eq--MI^32yJqufA>6Ah{Z2#s?LlW!d*DJeT=0DHbg@P-e!O zJ2SZ>$~d$ThKac&%w)wK(KM~M2Ywj%GnGFC_z}e%16-__VX{?R++L*@Vt$o?K(&cMB_UigvuRv+3j-EIUcs$nnm2u0BCyy`k&Z`zM&T z%05Mg@79;im?r;~E8v4Gu*@y)uiUMr9kyP(UgNoi`*3ELH8v{mZ`5d~fwJ*6llFrJ z$Chq)yIXS3vTaqZICd*P-ECr8GW=$(HhAB;WbtnEnEQ-Nn(r|WVxPU4dvIY3d{6H& zw|lS{{4e`(VNYZAI3E9YSUnCh0jtMBeuLHHco`hG4q3&1Tx^c9`7ibso^tT4!a8M# zaEjSz$M@3*$6K+ff0_m6ydMDP54cCetyfl$dlY}8sbI+|ef=AOxwrI@*G4%}zFA$& zsgVEbhBVB$u-om2_#PZ!y1J#qVr+Z5qOB*SU19F*#&1A0_u-pz94=J&?WVJ|dI}y@ zx6e&GnR~mL)4F7K*3`W0!hkYAEre&b@=JaL@T(>*C2FAg%GV*yWV(V%atn&eaE$& zD%zu%F>$J)Zn{oyE2evLNbwlx`9LvU!A}*x0G+24=RxKhJN5uYlc0!`_^5O&{;cgR z1D}Slb@G5`K&G3@aHpf6D8_RZFjVmfsW#Rrjf!76Q24Z6xM4x-|62ft_I(Z3_vyky6wmS@K)#x zW*YDU*_&Y^TGk;;jIz#pAs9KgN@>oemayd7%=l)}yYse#2leu}W-RdgB&*w&M%*Op}3l+1wwNUXJ;ICD@ z05#pK_;cv_SaB@q6~%iY<22*OZ%|r*>(mb624e1Nm#laS${wnCy$^2u>w)mFYbV2g z#>q93*^-_O@`}`uY?Cu2b&@&-p2BEu*P+AA_v?7l9CIuMHZ3d z$>CgB;|Iir2q`|5+hBSkfObor3D{cK?fod*k(Go%5h|=(=!> zs0UIz+08mfMPsgr_0x+F{0PI`GpVnBD`&0m-~qEM;yNZd>;_K!KW}Va^Qk%S@%{g2 z=H?$^4xM6bYz})kW~uv{xW6#T*YmBazkT8s-z|-Ww*Cy7>7gK?<{ufu*I_5~e zM_lLWHY3@ZJFw_oZ&XnXbeuP_L41_0i9>R}WS=+v-ARtDKX1ZYehp=?PPVMrrn2um z;xXJ0#2O%oKZi7HfPm+MZw(OeehIvQz%1Wu)=Yr)sLZ@z5>t;EXak$IN4VT?4S=Vk zj@B9g$D-75l}QF}r+AhezhEMUw?RP(%36cJ(_8T&h+0bl6>Gt>mI9csYQ7U$B*QEm zfhRsCY2TRG5n;$?tpivb!nD=_n42$I>j1nQ*jfkR|3k&CbpWnGRjhRY=E{(7UIU<2y6MRBwsWU9p5tuVJT}T zlIJVt97g-K6Nsi^3GhV|?p=hmI;JBJj}KLLq10SNP~cf)=WP6j0iiTvWdBI6p(HO~ zRrYNjjj?0o&eh~9=~0i@@G==wZ_Pt~Jzf_J8?%hkfks9XEixZW?V9Nx^HbNuU#_t+miDjN-bUSzY2(kLsG&x;*T!F%&GUN(M87d2| zpnq2>hp(7ecZ;TS`HESN(%_MO)d00z_ zp_yC~1f58liD?DWMlwk<eLPAYq{(m699k{N1%tGTS)(sO`ZvV6K+-VIZ@mfTXkR4nqX}MVbhF2qO$3 z^p|5`CnO{sA@q8{W)jjCNuw|p;tse&?hki5nr(wQA(SI=?tqT+B3V&gF)`HIg#mHS zkLa)^_3W8sKli=P_jH`It3_jWVO^5b=7x3wTX`8@*JS6T>kZU}m1fV%%?T*ZF3Bzk zn4Vu+=Kqj|x3_a&b@`{^@_BD3rsMa6c>!hF`O~l4!EV6~)Dx*FVQTevcXyDI6ldJ` zmO||I=~q*nCp|6MX|N^&Q|mC0#}C3LpT=X?2W^LwCqG7ds^W>jxVo1ACty3Q0-2t2 zsvm|!elJ1&oe0+@iSO^k#(xAQn^pKY@K(i#fnQfVRSJ;9`zBZylobuVwyy%cyQBu1 z@SU5zAVC3W!M68-lx=dZzmsKI$B>y7-6oR;IEk)wsRD5aG?6_6oNzSA!vmZ)sRCVzBco3tMV&RP7IH*9p_zERE%7jY~dLZpjHr3CaI5!!YuCa}n)_{5EAddmG*Hp99rR zi%JuVxRrl)w$uB1zKtw*p(NGc;E9Uq&`(pmQK|}@i1Ku(drVm_n70**aTf#DC~ktP{#@}PsN1BtBjle~%wR*U zVm>Y}E4~-}or*a{?+wKZfDhQtKI+Q>rh}T`KMF^M3K`!vNa0$w>~fOB2&L&ycP~hezEiO$Renn1<{6W5Ec>J;^dYY zPPn%M^;u6IUZ0ObcC)6}N%{=up=8dFYh#eCj!G=C*0u*RvRyoGXUV+5Ou-jrYFsr=@97p8@-KCd1|rK*Q~&E|EL^Xj5j`a|L{kbn?2zix#5c8UP(QxTZMOV z#rb+vI@PYGd||i)3jXsPpz7#_N%G=SrySCKn zZ(NV~ZhgwR-GxEAIV+tF?lwjuS28>|s(%MY9lmi$#PP2=$A-?H2-t1xRJLw17e hij?CdNfKBMQX$D8W-V^WlXfaYhAbe1-O`E7`wv=sXXF3? delta 53246 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 U&s}0?5W2xV0|xi?{+@CF7xwsH0RR91 From 3168ede2cbd3df99121944d46a5b24e9557d2b4b Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Fri, 24 Jun 2016 13:08:25 -0700 Subject: [PATCH 065/222] ATLEDGE-619: fix dtostrf Use a different method for float->string conversion, and fix the width calculation so that extra spaces are only printed if the width parameter exceeds the output string length (ie. a mininum width, as specified by dtostrf reference from avr-libc). --- cores/arduino/WString.cpp | 23 ------- cores/arduino/WString.h | 4 -- cores/arduino/stdlib_noniso.cpp | 107 +++++++++++++++++++------------- cores/arduino/stdlib_noniso.h | 2 + 4 files changed, 67 insertions(+), 69 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 6217a311..73a96f9f 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -813,26 +813,3 @@ float String::toFloat(void) const if (buffer) return float(atof(buffer)); return 0; } - -/*********************************************/ -/* utilities functions */ -/*********************************************/ - -int String::digitsBe4Decimal(double number) -{ - int cnt = 1; // Always has one digit - - // Count -ve sign as one digit - if(number < 0.0) { - cnt++; - number = -number; - } - - // Count the number of digits beyond the 1st, basically, the exponent. - while(number >= 10.0) { - number /= 10; - cnt++; - } - return cnt; -} - diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 1367d0ab..75a3e143 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -217,10 +217,6 @@ class String #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void move(String &rhs); #endif - - // utilities functions. - // Number of digits (including sign) in the integer portion of a float/double - int digitsBe4Decimal(double number); }; class StringSumHelper : public String diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 1fdf89c1..68c0ba39 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -24,6 +24,8 @@ #include "math.h" #include "inttypes.h" +#define ASCII_ZERO 0x30 + int atoi(const char* s) { return (int) atol(s); } @@ -162,7 +164,31 @@ void shiftOutDigit(double *number, int count, char *s) *number = tmp; } -char * dtostrf(double number, signed char width, unsigned char prec, char *s) { +int digitsBe4Decimal(double number) +{ + int cnt = 1; // Always has one digit + + // Count -ve sign as one digit + if(number < 0.0) { + cnt++; + number = -number; + } + + // Count the number of digits beyond the 1st, basically, the exponent. + while(number >= 10.0) { + number /= 10; + cnt++; + } + return cnt; +} + +char *dtostrf(double number, signed char width, unsigned char prec, char *s) +{ + char *out; + unsigned long long integer; + double fraction, rounding; + int digit, before, i; + int delta; if (isnan(number)) { strcpy(s, "nan"); @@ -173,62 +199,59 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) { return s; } - char *out = s; - int expCnt = 0, digit, totalWidth; - double tmp, rounding; + out = s; + before = digitsBe4Decimal(number); - // Check for left adjustment (spaces) - while(width < 0) { - *out++ = ' '; - width++; + // check if padding is required + if (width < 0) { + delta = (-width) - (before + prec + 1); + for (i = 0; i < delta; ++i) *out++ = ' '; + width = 0; } - totalWidth = (int)width; // Handle negative numbers if (number < 0.0) { - *out++ = '-'; + *out = '-'; number = -number; - if(totalWidth > 0) totalWidth--; } - // Rounding up to the precision - tmp = number; - rounding = 0.5; - for(int i=0; i < prec; i++) - rounding /= 10.0; - tmp += rounding; + // seperate integral and fractional parts + integer = (unsigned long long) number; + fraction = (double) (number - integer); - // Shifting the number to the right - while( tmp >= 10.0 ) { - tmp /= 10.0; - expCnt++; + // generate chars for each digit of the integral part + i = before; + while (integer > 10) { + digit = integer % 10; + out[(i--) - 1] = ASCII_ZERO + digit; + integer /= 10; } - // 1st, print the single digit left after shifting - digit = (int)tmp; - *out++ = '0' + digit; - tmp -= (double)digit; - if(totalWidth > 0) totalWidth--; + out[i - 1] = ASCII_ZERO + integer; + out += before; + if (!prec) goto end; - // Then the integer portion - shiftOutDigit(&tmp, expCnt, out); - out += expCnt; - if(totalWidth > 0) totalWidth -= expCnt; - - // Then the decimal portion - if( prec ) { - *out++ = '.'; - shiftOutDigit(&tmp, prec, out); - if(totalWidth > 0) totalWidth -= (prec + 1); - out += prec; + // rounding up to the precision + rounding = 0.5; + for (i = 0; i < prec; ++i) + rounding /= 10.0; + fraction += rounding; + + // generate chars for each digit of the fractional part + *out++ = '.'; + for (i = 0; i < prec; ++i) { + fraction *= 10.0; + digit = ((unsigned long long) fraction) % 10; + *out++ = (char) (ASCII_ZERO + digit); } - // Right adjustment - while(totalWidth > 0) { - *out++ = ' '; - totalWidth--; +end: + // check if padding is required + if (width > 0) { + delta = width - (before + prec + 1); + for (i = 0; i < delta; ++i) *out++ = ' '; } - *out = 0; // End of string + *out = 0; return s; } diff --git a/cores/arduino/stdlib_noniso.h b/cores/arduino/stdlib_noniso.h index 13b02887..707a7611 100644 --- a/cores/arduino/stdlib_noniso.h +++ b/cores/arduino/stdlib_noniso.h @@ -39,6 +39,8 @@ char* ultoa (unsigned long val, char *s, int radix); char* dtostrf (double val, signed char width, unsigned char prec, char *s); +int digitsBe4Decimal(double number); + #ifdef __cplusplus } // extern "C" #endif From ecee2e9483e39af71df873174df070fdf952c431 Mon Sep 17 00:00:00 2001 From: Caihong Ma Date: Mon, 4 Jul 2016 15:15:54 +0800 Subject: [PATCH 066/222] I2S DMA - supplement library and examples --- .../I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino | 99 +++ .../I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino | 69 ++ libraries/CurieI2S/keywords.txt | 106 +-- libraries/CurieI2S/src/CurieI2SDMA.cpp | 275 ++++++ libraries/CurieI2S/src/CurieI2SDMA.h | 81 ++ .../common/scss_registers.h | 32 + .../libarc32_arduino101/drivers/clk_system.c | 41 + .../libarc32_arduino101/drivers/clk_system.h | 64 ++ system/libarc32_arduino101/drivers/i2s_priv.h | 302 +++++++ system/libarc32_arduino101/drivers/soc_dma.c | 793 ++++++++++++++++++ system/libarc32_arduino101/drivers/soc_dma.h | 239 ++++++ .../drivers/soc_dma_priv.h | 339 ++++++++ system/libarc32_arduino101/drivers/soc_i2s.c | 672 +++++++++++++++ system/libarc32_arduino101/drivers/soc_i2s.h | 214 +++++ variants/arduino_101/libarc32drv_arduino101.a | Bin 431312 -> 488918 bytes 15 files changed, 3278 insertions(+), 48 deletions(-) create mode 100644 libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino create mode 100644 libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino create mode 100644 libraries/CurieI2S/src/CurieI2SDMA.cpp create mode 100644 libraries/CurieI2S/src/CurieI2SDMA.h create mode 100644 system/libarc32_arduino101/drivers/clk_system.c create mode 100644 system/libarc32_arduino101/drivers/clk_system.h create mode 100644 system/libarc32_arduino101/drivers/i2s_priv.h create mode 100644 system/libarc32_arduino101/drivers/soc_dma.c create mode 100644 system/libarc32_arduino101/drivers/soc_dma.h create mode 100644 system/libarc32_arduino101/drivers/soc_dma_priv.h create mode 100644 system/libarc32_arduino101/drivers/soc_i2s.c create mode 100644 system/libarc32_arduino101/drivers/soc_i2s.h diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino new file mode 100644 index 00000000..97ab8163 --- /dev/null +++ b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + +/** + * A simple sketch to test the rx channel of the i2s interface. + * A callback function is used to fill up a buffer whenever data is received + * + * To test this sketch you will need a second Arduino/Genuino 101 board with the I2SDMA_TxCallback sketch uploaded + * + * Connection: + * GND -> GND + * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) + * I2S_RWS(pin 3) -> I2S_TWS(pin 4) + * I2S_RXD(pin 5) -> I2S_TXD(pin 7) + * +**/ +#include + +#define BUFF_SIZE 128 +#define OFFSET 2 +uint32_t dataBuff[BUFF_SIZE+OFFSET]; // extra 2 buffer is for the padding zero + +uint8_t start_flag = 0; +uint8_t done_flag = 0; +uint32_t loop_count = 0; + +void setup() +{ + Serial.begin(115200); + while(!Serial); + Serial.println("CurieI2SDMA Rx Callback"); + + CurieI2SDMA.iniRX(); + /* + * CurieI2SDMA.beginTX(sample_rate, resolution, master,mode) + * mode 1 : PHILIPS_MODE + * 2 : RIGHT_JST_MODE + * 3 : LEFT_JST_MODE + * 4 : DSP_MODE + */ + CurieI2SDMA.beginRX(44100, 32,0,1); + +} + +void loop() +{ + int status = CurieI2SDMA.transRX(dataBuff,sizeof(dataBuff)); + if(status) + return; + + if(start_flag) + { + if((dataBuff[OFFSET]>>16) != loop_count+1) + Serial.println("+++ loop_count jump +++"); + } + else + { + start_flag = 1; + } + loop_count = (dataBuff[OFFSET] >> 16); + + done_flag = 1; + for(uint32_t i = 0 ;i < BUFF_SIZE;++i) + { + //Serial.println(dataBuff[i+OFFSET],HEX); + if ((dataBuff[i+OFFSET] & 0XFFFF0000) == (loop_count <<16) + && (dataBuff[i+OFFSET] & 0XFFFF) == (i+1)) + ; + else + { + done_flag = 0; + Serial.println(dataBuff[i+OFFSET],HEX); + Serial.println("ERROR"); + break; + } + } + + if(done_flag) + Serial.println("RX done"); + delay(100); +} + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + 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 +*/ \ No newline at end of file diff --git a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino new file mode 100644 index 00000000..fe27ab2e --- /dev/null +++ b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + +//I2S_TX -> Pin 7 +//I2S_TSK -> Pin 4 +//I2S_TSCK -> pin 2 + +#include + +#define BUFF_SIZE 128 +boolean blinkState = true; // state of the LED +uint32_t dataBuff[BUFF_SIZE]; +uint32_t loop_count = 0; +void setup() +{ + Serial.begin(115200); + while(!Serial); + Serial.println("CurieI2SDMA Tx Callback"); + + CurieI2SDMA.iniTX(); + /* + * CurieI2SDMA.beginTX(sample_rate, resolution, master,mode) + * mode 1 : PHILIPS_MODE + * 2 : RIGHT_JST_MODE + * 3 : LEFT_JST_MODE + * 4 : DSP_MODE + */ + CurieI2SDMA.beginTX(44100, 32,1, 1); + digitalWrite(13, blinkState); +} + +void loop() +{ + for(uint32_t i = 0; i + +static void txi2s_done(void* x); +static void rxi2s_done(void* x); +static void txi2s_err(void* x); +static void rxi2s_err(void* x); + +volatile uint8_t txdone_flag = 0; +volatile uint8_t txerror_flag = 0; + +volatile uint8_t rxdone_flag = 0; +volatile uint8_t rxerror_flag = 0; + + +static void txi2s_done(void* x) +{ + txdone_flag = 1; + + return; +} + +static void rxi2s_done(void* x) +{ + rxdone_flag = 1; + + return; +} + +static void txi2s_err(void* x) +{ + txerror_flag = 1; + + return; +} + +static void rxi2s_err(void* x) +{ + rxerror_flag = 1; + + return; +} + +struct soc_i2s_cfg txcfg ; + +struct soc_i2s_cfg rxcfg ; + +Curie_I2SDMA CurieI2SDMA; + +Curie_I2SDMA::Curie_I2SDMA() +{ +} + +int Curie_I2SDMA::iniTX() +{ + muxTX(1); + soc_i2s_init(); + soc_dma_init(); + return I2S_DMA_OK; +} + +int Curie_I2SDMA::iniRX() +{ + muxRX(1); + soc_i2s_init(); + soc_dma_init(); + return I2S_DMA_OK; +} + +void Curie_I2SDMA::muxTX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = I2S_MUX_MODE; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(g_APinDescription[I2S_TXD].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TWS].ulSocPin, mux_mode); + SET_PIN_MODE(g_APinDescription[I2S_TSCK].ulSocPin, mux_mode); + g_APinDescription[I2S_TXD].ulPinMode = mux_mode; + g_APinDescription[I2S_TWS].ulPinMode = mux_mode; + g_APinDescription[I2S_TSCK].ulPinMode = mux_mode; +} + +void Curie_I2SDMA::muxRX(bool enable) +{ + int mux_mode = GPIO_MUX_MODE; + if(enable) + { + mux_mode = I2S_MUX_MODE; + } + + /* Set SoC pin mux configuration */ + SET_PIN_MODE(49, mux_mode); //I2S_RXD + SET_PIN_MODE(51, mux_mode); //I2S_RWS + SET_PIN_MODE(50, mux_mode); //I2S_RSCK + g_APinDescription[I2S_RXD].ulPinMode = mux_mode; + g_APinDescription[I2S_RWS].ulPinMode = mux_mode; + g_APinDescription[I2S_RSCK].ulPinMode = mux_mode; +} + +int Curie_I2SDMA::beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode) +{ + switch(mode) + { + case 1: + mode = I2S_MODE_PHILLIPS ; + break; + case 2: + mode = I2S_MODE_RJ; + break; + case 3: + mode = I2S_MODE_LJ; + break; + case 4: + mode = I2S_MODE_DSP; + break; + default: + break; + } + + txcfg.sample_rate = sample_rate; + txcfg.resolution = resolution; + txcfg.mode = mode; + txcfg.master = master; + txcfg.cb_done = txi2s_done; + txcfg.cb_err = txi2s_err; + txdone_flag = 0; + txerror_flag = 0; + soc_i2s_config(I2S_CHANNEL_TX, &txcfg); + + return I2S_DMA_OK; +} + +int Curie_I2SDMA::beginRX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode) +{ + switch(mode) + { + case 1: + mode = I2S_MODE_PHILLIPS ; + break; + case 2: + mode = I2S_MODE_RJ; + break; + case 3: + mode = I2S_MODE_LJ; + break; + case 4: + mode = I2S_MODE_DSP; + break; + default: + break; + } + + rxcfg.sample_rate = sample_rate; + rxcfg.resolution = resolution; + rxcfg.mode = mode; + rxcfg.master = master; + + rxcfg.cb_done = rxi2s_done; + rxcfg.cb_err = rxi2s_err; + + rxdone_flag = 0; + rxerror_flag = 0; + + soc_i2s_config(I2S_CHANNEL_RX, &rxcfg); + + return I2S_DMA_OK; +} + +int Curie_I2SDMA::transTX(uint32_t* buf_TX,uint32_t len) +{ + soc_i2s_stream(buf_TX, len,0); + + while (1) + { + // check the DMA and I2S status + if(txdone_flag && !txerror_flag) + { + txdone_flag = 0; + txerror_flag = 0; + return I2S_DMA_OK; + } + if(txerror_flag) + { + return I2S_DMA_FAIL; + } + } +} + +int Curie_I2SDMA::transRX(uint32_t* buf_RX,uint32_t len) +{ + soc_i2s_listen(buf_RX, len ,0); + + while (1) + { + // check the DMA and I2S status + if(rxdone_flag && !rxerror_flag) + { + rxdone_flag = 0; + rxerror_flag = 0; + return I2S_DMA_OK; + } + if(rxerror_flag) + { + return I2S_DMA_FAIL; + } + } + return I2S_DMA_OK; +} + +void Curie_I2SDMA::stopTX() +{ + soc_i2s_stop_stream(); + muxTX(0); +} + +void Curie_I2SDMA::stopRX() +{ + soc_i2s_stop_listen(); + muxRX(0); +} + +int Curie_I2SDMA::mergeData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_TX) +{ + int length = (int)(sizeof(buf_left) / sizeof(buf_left[0])); + for(int i = 0; i < length;++i) + { + buf_TX[2*i] = buf_left[i]; + buf_TX[2*i+1] = buf_right[i]; + } + + return I2S_DMA_OK; +} + +int Curie_I2SDMA::separateData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_RX) +{ + int length1 = (int)( sizeof(buf_RX) / sizeof(buf_RX[0])/2 ); + int length2 = (int)( sizeof(buf_left) / sizeof(buf_left[0]) ); + int length = length1 < length2 ? length1 : length2; + + for(int i = 0; i < length;++i) + { + buf_left[i] = buf_RX[2*i]; + buf_right[i] = buf_RX[2*i+1]; + } + return I2S_DMA_OK; +} diff --git a/libraries/CurieI2S/src/CurieI2SDMA.h b/libraries/CurieI2S/src/CurieI2SDMA.h new file mode 100644 index 00000000..a1707123 --- /dev/null +++ b/libraries/CurieI2S/src/CurieI2SDMA.h @@ -0,0 +1,81 @@ +//*************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// +// 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 +// +//*************************************************************** + +//CurieI2SDMA.h + +#ifndef _CURI2SDMA_H_ +#define _CURI2SDMA_H_ + +#include + +//I2S Arduino Pins +#define I2S_TXD 7 +#define I2S_TWS 4 +#define I2S_TSCK 2 +#define I2S_RXD 5 +#define I2S_RWS 3 +#define I2S_RSCK 8 + +#define I2S_DMA_OK 0 +#define I2S_DMA_FAIL 1 +class Curie_I2SDMA +{ + private: + // mux/demux the i2s rx pins into i2s mode + void muxRX(bool enable); + + // mux/demux the i2s tx pins into i2s mode + void muxTX(bool enable); + + public: + Curie_I2SDMA(); + + // + int beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode); + // + int beginRX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode); + + // initializes i2s interface + int iniTX(); + //void transTX(); + int iniRX(); + + // starts transmission of data to the tx channel + int transTX(uint32_t* buf_TX,uint32_t len); + + // starts listening to the rx channel + int transRX(uint32_t* buf_RX,uint32_t len); + + // merge data of left and right channel into one buffer + int mergeData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_TX); + + // seperate the data to left and right channl + int separateData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_RX); + + // + void stopTX(); + // + void stopRX(); + +}; + +extern Curie_I2SDMA CurieI2SDMA; + +#endif diff --git a/system/libarc32_arduino101/common/scss_registers.h b/system/libarc32_arduino101/common/scss_registers.h index ddf393f4..600459a4 100644 --- a/system/libarc32_arduino101/common/scss_registers.h +++ b/system/libarc32_arduino101/common/scss_registers.h @@ -120,6 +120,8 @@ #define QRK_CLKGATE_CTRL_PWM_ENABLE (1 << 12) #define PERIPH_CLK_GATE_CTRL (SCSS_REGISTER_BASE + 0x018) +#define MLAYER_AHB_CTL (SCSS_REGISTER_BASE + 0x034) +#define SS_PERIPH_CLK_GATE_CTL (SCSS_REGISTER_BASE + 0x028) /* PWM */ #define QRK_PWM_BASE_ADDR 0xB0000800 @@ -216,6 +218,9 @@ #define QRK_RTC_ENABLE (1 << 2) #define QRK_RTC_WRAP_ENABLE (1 << 3) +/* DMA */ +#define SOC_DMA_BASE (0xB0700000) + /* MPR */ #define QRK_MPR_BASE_ADDR 0xB0400000 #define QRK_MPR_REGS_LEN 0x04 @@ -244,6 +249,9 @@ #define SOC_MST_SPI1_REGISTER_BASE (0xB0001400) #define SOC_SLV_SPI_REGISTER_BASE (0xB0001800) +/* I2S */ +#define SOC_I2S_BASE (0xB0003800) + /* Mailbox Interrupt*/ #define IO_REG_MAILBOX_INT_MASK (SCSS_REGISTER_BASE + 0x4A0) @@ -392,11 +400,21 @@ #define SOC_SPIS0_INTERRUPT 0x4 #define SOC_UART0_INTERRUPT 0x5 #define SOC_UART1_INTERRUPT 0x6 +#define SOC_I2S_INTERRUPT 0x7 #define SOC_GPIO_INTERRUPT 0x8 #define SOC_PWM_INTERRUPT 0x9 #define SOC_RTC_INTERRUPT 0xb #define SOC_WDT_INTERRUPT 0xc +#define SOC_DMA_CHANNEL0_INTERRUPT 0xd +#define SOC_DMA_CHANNEL1_INTERRUPT 0xe +#define SOC_DMA_CHANNEL2_INTERRUPT 0xf +#define SOC_DMA_CHANNEL3_INTERRUPT 0x10 +#define SOC_DMA_CHANNEL4_INTERRUPT 0x11 +#define SOC_DMA_CHANNEL5_INTERRUPT 0x12 +#define SOC_DMA_CHANNEL6_INTERRUPT 0x13 +#define SOC_DMA_CHANNEL7_INTERRUPT 0x14 #define SOC_MBOX_INTERRUPT 0x15 +#define SOC_DMA_ERR_INTERRUPT 0x18 #define SOC_MPR_INTERRUPT 0x19 #define SOC_GPIO_AON_INTERRUPT 0x1F @@ -411,9 +429,19 @@ #define SOC_SPIS0_INTERRUPT (40) #define SOC_UART0_INTERRUPT (41) #define SOC_UART1_INTERRUPT (42) +#define SOC_I2S_INTERRUPT (43) #define SOC_GPIO_INTERRUPT (44) #define SOC_PWM_INTERRUPT (45) +#define SOC_DMA_CHANNEL0_INTERRUPT (49) +#define SOC_DMA_CHANNEL1_INTERRUPT (50) +#define SOC_DMA_CHANNEL2_INTERRUPT (51) +#define SOC_DMA_CHANNEL3_INTERRUPT (52) +#define SOC_DMA_CHANNEL4_INTERRUPT (53) +#define SOC_DMA_CHANNEL5_INTERRUPT (54) +#define SOC_DMA_CHANNEL6_INTERRUPT (55) +#define SOC_DMA_CHANNEL7_INTERRUPT (56) #define SOC_MBOX_INTERRUPT (57) +#define SOC_DMA_ERR_INTERRUPT (60) #define SOC_GPIO_AON_INTERRUPT (67) #define DRV_REG(_driver_) (MMIO_REG_VAL_FROM_BASE(SCSS_REGISTER_BASE, _driver_)) @@ -424,4 +452,8 @@ #endif +/* Clock gate mask */ +#define I2C0_CLK_GATE_MASK 0x00080004 +#define I2C1_CLK_GATE_MASK 0x00100008 +#define I2S_CLK_GATE_MASK 0x00200200 #endif /* SCSS_REGISTERS_H_ */ diff --git a/system/libarc32_arduino101/drivers/clk_system.c b/system/libarc32_arduino101/drivers/clk_system.c new file mode 100644 index 00000000..a3b57c79 --- /dev/null +++ b/system/libarc32_arduino101/drivers/clk_system.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "clk_system.h" +#include "scss_registers.h" + +void set_clock_gate(struct clk_gate_info_s* clk_gate_info, uint32_t value) +{ + uint32_t tmp ; + tmp = MMIO_REG_VAL(clk_gate_info->clk_gate_register); + tmp &= ~(clk_gate_info->bits_mask); + tmp |= ((clk_gate_info->bits_mask) & value); + MMIO_REG_VAL(clk_gate_info->clk_gate_register) = tmp; +} diff --git a/system/libarc32_arduino101/drivers/clk_system.h b/system/libarc32_arduino101/drivers/clk_system.h new file mode 100644 index 00000000..99b8e748 --- /dev/null +++ b/system/libarc32_arduino101/drivers/clk_system.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CLK_SYSTEM_H_ +#define CLK_SYSTEM_H_ + +#include + +#define CLK_GATE_OFF (0) +#define CLK_GATE_ON (~CLK_GATE_OFF) + +/** + * @defgroup clk_gate Clock gating driver + * Clk Gate driver API. + * @ingroup common_drivers + * @{ + */ + +/** + * Clock gate data which contain register and bits implicated. + */ +struct clk_gate_info_s { + uint32_t clk_gate_register; /*!< register changed for clock gate */ + uint32_t bits_mask; /*!< mask used for clock gate */ +}; + +/** +* Configure clock gate to specified device +* +* @param clk_gate_info : pointer to a clock gate data structure +* @param value : state of clock gate desired +*/ +void set_clock_gate(struct clk_gate_info_s* clk_gate_info, uint32_t value); + +/** @} */ + +#endif /* CLK_SYSTEM_H_ */ diff --git a/system/libarc32_arduino101/drivers/i2s_priv.h b/system/libarc32_arduino101/drivers/i2s_priv.h new file mode 100644 index 00000000..6b90af1a --- /dev/null +++ b/system/libarc32_arduino101/drivers/i2s_priv.h @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef I2S_PRIV_H_ +#define I2S_PRIV_H_ + +#include "soc_i2s.h" + +#define I2S_TFIFO_SIZE 4 +#define I2S_RFIFO_SIZE 4 + +#define I2S_RFIFO_THR 1 +#define I2S_TFIFO_THR 1 + +// I2S Registers (from base register) and fields +#define SOC_I2S_CTRL (0x00) +#define SOC_I2S_CTRL_EN_0 (0) +#define SOC_I2S_CTRL_EN_1 (1) +#define SOC_I2S_CTRL_TR_CFG_0 (8) +#define SOC_I2S_CTRL_TR_CFG_1 (9) +#define SOC_I2S_CTRL_LOOP_BACK_0_1 (16) +#define SOC_I2S_CTRL_SFR_RST (20) +#define SOC_I2S_CTRL_T_MS (21) +#define SOC_I2S_CTRL_R_MS (22) +#define SOC_I2S_CTRL_TFIFO_RST (23) +#define SOC_I2S_CTRL_RFIFO_RST (24) +#define SOC_I2S_CTRL_TSYNC_RST (25) +#define SOC_I2S_CTRL_RSYNC_RST (26) +#define SOC_I2S_CTRL_TSYNC_LOOP_BACK (27) +#define SOC_I2S_CTRL_RSYNC_LOOP_BACK (28) + +#define SOC_I2S_STAT (0x04) +#define SOC_I2S_STAT_TDATA_UNDERR (0) +#define SOC_I2S_STAT_UNDERR_CODE (1) +#define SOC_I2S_STAT_RDATA_OVRERR (4) +#define SOC_I2S_STAT_OVRERR_CODE (5) +#define SOC_I2S_STAT_TFIFO_EMPTY (8) +#define SOC_I2S_STAT_TFIFO_AEMPTY (9) +#define SOC_I2S_STAT_TFIFO_FULL (10) +#define SOC_I2S_STAT_TFIFO_AFULL (11) +#define SOC_I2S_STAT_RFIFO_EMPTY (12) +#define SOC_I2S_STAT_RFIFO_AEMPTY (13) +#define SOC_I2S_STAT_RFIFO_FULL (14) +#define SOC_I2S_STAT_RFIFO_AFULL (15) + +#define SOC_I2S_SRR (0x08) +#define SOC_I2S_SRR_TSAMPLE_RATE (0) +#define SOC_I2S_SRR_TRESOLUTION (11) +#define SOC_I2S_SRR_RSAMPLE_RATE (16) +#define SOC_I2S_SRR_RRESOLUTION (27) + +#define SOC_I2S_CID_CTRL (0x0C) +#define SOC_I2S_CID_CTRL_STROBE_0 (0) +#define SOC_I2S_CID_CTRL_STROBE_1 (1) +#define SOC_I2S_CID_CTRL_STROBE_TS (8) +#define SOC_I2S_CID_CTRL_STROBE_RS (9) +#define SOC_I2S_CID_CTRL_INTREQ_MASK (15) +#define SOC_I2S_CID_CTRL_MASK_0 (16) +#define SOC_I2S_CID_CTRL_MASK_1 (17) +#define SOC_I2S_CID_CTRL_TFIFO_EMPTY_MASK (24) +#define SOC_I2S_CID_CTRL_TFIFO_AEMPTY_MASK (25) +#define SOC_I2S_CID_CTRL_TFIFO_FULL_MASK (26) +#define SOC_I2S_CID_CTRL_TFIFO_AFULL_MASK (27) +#define SOC_I2S_CID_CTRL_RFIFO_EMPTY_MASK (28) +#define SOC_I2S_CID_CTRL_RFIFO_AEMPTY_MASK (29) +#define SOC_I2S_CID_CTRL_RFIFO_FULL_MASK (30) +#define SOC_I2S_CID_CTRL_RFIFO_AFULL_MASK (31) + +#define SOC_I2S_TFIFO_STAT (0x10) + +#define SOC_I2S_RFIFO_STAT (0x14) + +#define SOC_I2S_TFIFO_CTRL (0x18) +#define SOC_I2S_TFIFO_CTRL_TAEMPTY_THRS (0) +#define SOC_I2S_TFIFO_CTRL_TAFULL_THRS (16) + +#define SOC_I2S_RFIFO_CTRL (0x1C) +#define SOC_I2S_RFIFO_CTRL_RAEMPTY_THRS (0) +#define SOC_I2S_RFIFO_CTRL_RAFULL_THRS (16) + +#define SOC_I2S_DEV_CONF (0x20) +#define SOC_I2S_DEV_CONF_TRAN_SCK_POLAR (0) +#define SOC_I2S_DEV_CONF_TRAN_WS_POLAR (1) +#define SOC_I2S_DEV_CONF_TRAN_ABP_ALIGN_LR (2) +#define SOC_I2S_DEV_CONF_TRAN_I2S_ALIGN_LR (3) +#define SOC_I2S_DEV_CONF_TRAN_DATA_WS_DEL (4) +#define SOC_I2S_DEV_CONF_TRAN_WS_DSP_MODE (5) +#define SOC_I2S_DEV_CONF_REC_SCK_POLAR (6) +#define SOC_I2S_DEV_CONF_REC_WS_POLAR (7) +#define SOC_I2S_DEV_CONF_REC_ABP_ALIGN_LR (8) +#define SOC_I2S_DEV_CONF_REC_I2S_ALIGN_LR (9) +#define SOC_I2S_DEV_CONF_REC_DATA_WS_DEL (10) +#define SOC_I2S_DEV_CONF_REC_WS_DSP_MODE (11) + +#define SOC_I2S_DATA_REG (0x50) + +struct i2s_channel_regs { + // CRTL Register + uint8_t ctrl; + uint8_t ctrl_en; + uint8_t ctrl_tr_cfg; + uint8_t ctrl_ms; + uint8_t ctrl_fifo_rst; + uint8_t ctrl_sync_rst; + uint8_t ctrl_sync_loopback; + + // STAT Register + uint8_t stat; + uint8_t stat_err; + uint8_t stat_code; + uint8_t stat_fifo_empty; + uint8_t stat_fifo_aempty; + uint8_t stat_fifo_full; + uint8_t stat_fifo_afull; + uint32_t stat_mask; + + // SRR Register + uint8_t srr; + uint8_t srr_sample_rate; + uint8_t srr_resolution; + uint32_t srr_mask; + + // CID CTRL Register + uint8_t cid_ctrl; + uint8_t cid_ctrl_strobe; + uint8_t cid_ctrl_strobe_sync; + uint8_t cid_ctrl_mask; + uint8_t cid_ctrl_fifo_empty_mask; + uint8_t cid_ctrl_fifo_aempty_mask; + uint8_t cid_ctrl_fifo_full_mask; + uint8_t cid_ctrl_fifo_afull_mask; + + // FIFO STAT Register + uint8_t fifo_stat; + + // FIFO CTRL Register + uint8_t fifo_ctrl; + uint8_t fifo_ctrl_aempty_thr; + uint8_t fifo_ctrl_afull_thr; + + // DEV CONF Register + uint8_t dev_conf; + uint8_t dev_conf_sck_polar; + uint8_t dev_conf_ws_polar; + uint8_t dev_conf_abp_align_lr; + uint8_t dev_conf_i2s_align_lr; + uint8_t dev_conf_data_ws_del; + uint8_t dev_conf_ws_dsp_mode; + uint32_t dev_conf_mask; + + // DATA Register + uint8_t data_reg; +}; + +const struct i2s_channel_regs i2s_reg_map[I2S_NUM_CHANNELS] = { + // TX Channel + { + // CRTL Register + .ctrl = SOC_I2S_CTRL, + .ctrl_en = SOC_I2S_CTRL_EN_0, + .ctrl_tr_cfg = SOC_I2S_CTRL_TR_CFG_0, + .ctrl_ms = SOC_I2S_CTRL_T_MS, + .ctrl_fifo_rst = SOC_I2S_CTRL_TFIFO_RST, + .ctrl_sync_rst = SOC_I2S_CTRL_TSYNC_RST, + .ctrl_sync_loopback = SOC_I2S_CTRL_TSYNC_LOOP_BACK, + + // STAT Register + .stat = SOC_I2S_STAT, + .stat_err = SOC_I2S_STAT_TDATA_UNDERR, + .stat_code = SOC_I2S_STAT_UNDERR_CODE, + .stat_fifo_empty = SOC_I2S_STAT_TFIFO_EMPTY, + .stat_fifo_aempty = SOC_I2S_STAT_TFIFO_AEMPTY, + .stat_fifo_full = SOC_I2S_STAT_TFIFO_FULL, + .stat_fifo_afull = SOC_I2S_STAT_TFIFO_AFULL, + .stat_mask = 0x00000F0F, + + // SRR Register + .srr = SOC_I2S_SRR, + .srr_sample_rate = SOC_I2S_SRR_TSAMPLE_RATE, + .srr_resolution = SOC_I2S_SRR_TRESOLUTION, + .srr_mask = 0x0000FFFF, + + // CID CTRL Register + .cid_ctrl = SOC_I2S_CID_CTRL, + .cid_ctrl_strobe = SOC_I2S_CID_CTRL_STROBE_0, + .cid_ctrl_strobe_sync = SOC_I2S_CID_CTRL_STROBE_TS, + .cid_ctrl_mask = SOC_I2S_CID_CTRL_MASK_0, + .cid_ctrl_fifo_empty_mask = SOC_I2S_CID_CTRL_TFIFO_EMPTY_MASK, + .cid_ctrl_fifo_aempty_mask = SOC_I2S_CID_CTRL_TFIFO_AEMPTY_MASK, + .cid_ctrl_fifo_full_mask = SOC_I2S_CID_CTRL_TFIFO_FULL_MASK, + .cid_ctrl_fifo_afull_mask = SOC_I2S_CID_CTRL_TFIFO_AFULL_MASK, + + // FIFO STAT Register + .fifo_stat = SOC_I2S_TFIFO_STAT, + + // FIFO CTRL Register + .fifo_ctrl = SOC_I2S_TFIFO_CTRL, + .fifo_ctrl_aempty_thr = SOC_I2S_TFIFO_CTRL_TAEMPTY_THRS, + .fifo_ctrl_afull_thr = SOC_I2S_TFIFO_CTRL_TAFULL_THRS, + + // DEV CONF Register + .dev_conf = SOC_I2S_DEV_CONF, + .dev_conf_sck_polar = SOC_I2S_DEV_CONF_TRAN_SCK_POLAR, + .dev_conf_ws_polar = SOC_I2S_DEV_CONF_TRAN_WS_POLAR, + .dev_conf_abp_align_lr = SOC_I2S_DEV_CONF_TRAN_ABP_ALIGN_LR, + .dev_conf_i2s_align_lr = SOC_I2S_DEV_CONF_TRAN_I2S_ALIGN_LR, + .dev_conf_data_ws_del = SOC_I2S_DEV_CONF_TRAN_DATA_WS_DEL, + .dev_conf_ws_dsp_mode = SOC_I2S_DEV_CONF_TRAN_WS_DSP_MODE, + .dev_conf_mask = 0x0000003F, + + // DATA Register + .data_reg = SOC_I2S_DATA_REG + }, + + // RX Channel + { + // CRTL Register + .ctrl = SOC_I2S_CTRL, + .ctrl_en = SOC_I2S_CTRL_EN_1, + .ctrl_tr_cfg = SOC_I2S_CTRL_TR_CFG_1, + .ctrl_ms = SOC_I2S_CTRL_R_MS, + .ctrl_fifo_rst = SOC_I2S_CTRL_RFIFO_RST, + .ctrl_sync_rst = SOC_I2S_CTRL_RSYNC_RST, + .ctrl_sync_loopback = SOC_I2S_CTRL_RSYNC_LOOP_BACK, + + // STAT Register + .stat = SOC_I2S_STAT, + .stat_err = SOC_I2S_STAT_RDATA_OVRERR, + .stat_code = SOC_I2S_STAT_OVRERR_CODE, + .stat_fifo_empty = SOC_I2S_STAT_RFIFO_EMPTY, + .stat_fifo_aempty = SOC_I2S_STAT_RFIFO_AEMPTY, + .stat_fifo_full = SOC_I2S_STAT_RFIFO_FULL, + .stat_fifo_afull = SOC_I2S_STAT_RFIFO_AFULL, + .stat_mask = 0x0000F0F0, + + // SRR Register + .srr = SOC_I2S_SRR, + .srr_sample_rate = SOC_I2S_SRR_RSAMPLE_RATE, + .srr_resolution = SOC_I2S_SRR_RRESOLUTION, + .srr_mask = 0xFFFF0000, + + // CID CTRL Register + .cid_ctrl = SOC_I2S_CID_CTRL, + .cid_ctrl_strobe = SOC_I2S_CID_CTRL_STROBE_1, + .cid_ctrl_strobe_sync = SOC_I2S_CID_CTRL_STROBE_RS, + .cid_ctrl_mask = SOC_I2S_CID_CTRL_MASK_1, + .cid_ctrl_fifo_empty_mask = SOC_I2S_CID_CTRL_RFIFO_EMPTY_MASK, + .cid_ctrl_fifo_aempty_mask = SOC_I2S_CID_CTRL_RFIFO_AEMPTY_MASK, + .cid_ctrl_fifo_full_mask = SOC_I2S_CID_CTRL_RFIFO_FULL_MASK, + .cid_ctrl_fifo_afull_mask = SOC_I2S_CID_CTRL_RFIFO_AFULL_MASK, + + // FIFO STAT Register + .fifo_stat = SOC_I2S_RFIFO_STAT, + + // FIFO CTRL Register + .fifo_ctrl = SOC_I2S_RFIFO_CTRL, + .fifo_ctrl_aempty_thr = SOC_I2S_RFIFO_CTRL_RAEMPTY_THRS, + .fifo_ctrl_afull_thr = SOC_I2S_RFIFO_CTRL_RAFULL_THRS, + + // DEV CONF Register + .dev_conf = SOC_I2S_DEV_CONF, + .dev_conf_sck_polar = SOC_I2S_DEV_CONF_REC_SCK_POLAR, + .dev_conf_ws_polar = SOC_I2S_DEV_CONF_REC_WS_POLAR, + .dev_conf_abp_align_lr = SOC_I2S_DEV_CONF_REC_ABP_ALIGN_LR, + .dev_conf_i2s_align_lr = SOC_I2S_DEV_CONF_REC_I2S_ALIGN_LR, + .dev_conf_data_ws_del = SOC_I2S_DEV_CONF_REC_DATA_WS_DEL, + .dev_conf_ws_dsp_mode = SOC_I2S_DEV_CONF_REC_WS_DSP_MODE, + .dev_conf_mask = 0x00000FC0, + + // DATA Register + .data_reg = SOC_I2S_DATA_REG + } +}; + +#endif /* I2S_PRIV_H_ */ diff --git a/system/libarc32_arduino101/drivers/soc_dma.c b/system/libarc32_arduino101/drivers/soc_dma.c new file mode 100644 index 00000000..f0b0120c --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_dma.c @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "scss_registers.h" +#include "portable.h" +#include "os/os.h" +#include "data_type.h" +#include "clk_system.h" + +#include "soc_dma.h" +#include "soc_dma_priv.h" + +// Some useful helper macros for setting and clearing bits and values (NR: dont read the value first) +// x - address or variable +// f - bit field to set or clear +#define SETB(x, f) ((x) |= (1 << (f))) +#define CLRB(x, f) ((x) &= ~(1 << (f))) + +#define SETB_NR(x, f) ((x) = (1 << (f))) +#define CLRB_NR(x, f) ((x) = ~(1 << (f))) + +// x - address or variable +// f - starting bit for value +// l - length of value +// v - value to set +#define SETV(x, f, l, v) ((x) &= ~(((1 << (l)) - 1) << (f))); \ + ((x) |= ((((1 << (l)) - 1) & (v)) << (f))) + +#define SETV_NR(x, f, l, v) ((x) = ((((1 << (l)) - 1) & (v)) << (f))) + +// Function Prototypes +static void dma_disable(struct soc_dma_channel *channel); +static void dma_enable(struct soc_dma_channel *channel); +static struct soc_dma_xfer_item *dma_find_list_end(struct soc_dma_xfer_item *head); +static struct dma_lli *dma_find_ll_end(struct dma_lli *head); +static DRIVER_API_RC dma_create_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg); +static void dma_interrupt_handler(void *num); +DRIVER_API_RC soc_dma_config(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg); +DRIVER_API_RC soc_dma_deconfig(struct soc_dma_channel *channel); +DRIVER_API_RC soc_dma_acquire(struct soc_dma_channel *channel); +DRIVER_API_RC soc_dma_release(struct soc_dma_channel *channel); +DRIVER_API_RC soc_dma_start_transfer(struct soc_dma_channel *channel); +DRIVER_API_RC soc_dma_stop_transfer(struct soc_dma_channel *channel); +DRIVER_API_RC soc_dma_alloc_list_item(struct soc_dma_xfer_item **ret, struct soc_dma_xfer_item *base); +DRIVER_API_RC soc_dma_free_list(struct soc_dma_cfg *cfg); +DRIVER_API_RC dma_init(); + +DECLARE_INTERRUPT_HANDLER static void dma_ch0_interrupt_handler() +{ + dma_interrupt_handler((void *)0); +} + +DECLARE_INTERRUPT_HANDLER static void dma_ch1_interrupt_handler() +{ + dma_interrupt_handler((void *)1); +} + +struct soc_dma_info g_dma_info = { + .int_mask = { + INT_DMA_CHANNEL_0_MASK, + INT_DMA_CHANNEL_1_MASK, + INT_DMA_CHANNEL_2_MASK, + INT_DMA_CHANNEL_3_MASK, + INT_DMA_CHANNEL_4_MASK, + INT_DMA_CHANNEL_5_MASK, + INT_DMA_CHANNEL_6_MASK, + INT_DMA_CHANNEL_7_MASK + }, + .int_vector = { + SOC_DMA_CHANNEL0_INTERRUPT, + SOC_DMA_CHANNEL1_INTERRUPT, + SOC_DMA_CHANNEL2_INTERRUPT, + SOC_DMA_CHANNEL3_INTERRUPT, + SOC_DMA_CHANNEL4_INTERRUPT, + SOC_DMA_CHANNEL5_INTERRUPT, + SOC_DMA_CHANNEL6_INTERRUPT, + SOC_DMA_CHANNEL7_INTERRUPT + }, + .int_handler = { + dma_ch0_interrupt_handler, + dma_ch1_interrupt_handler, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }, + .err_mask = INT_DMA_ERROR_MASK, + .err_vector = SOC_DMA_ERR_INTERRUPT +}; + +static struct soc_dma_info* dma_info = &g_dma_info; + +/* Internal Functions */ +static void dma_disable(struct soc_dma_channel *channel) +{ + uint32_t reg; + + // Turn off the given channel + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CH_EN_REG); + SETB(reg, SOC_DMA_CH_EN_REG_CH_EN_WE + (channel->id)); + CLRB(reg, SOC_DMA_CH_EN_REG_CH_EN + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CH_EN_REG) = reg; + + // Clear interrupts and disable them + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_TFR), SOC_DMA_CLEAR_CLEAR + (channel->id)); + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_BLOCK), SOC_DMA_CLEAR_CLEAR + (channel->id)); + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_ERR), SOC_DMA_CLEAR_CLEAR + (channel->id)); + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_TFR); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + CLRB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_TFR) = reg; + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_BLOCK); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + CLRB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_BLOCK) = reg; + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_ERR); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + CLRB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_ERR) = reg; + + CLRB(dma_regs[channel->id].CTL_L, SOC_DMA_CTL_L_INT_EN); + + // Deactivate channel + channel->active = 0; + CLRB(dma_info->active, channel->id); + + return; +} + +static void dma_enable(struct soc_dma_channel *channel) +{ + uint32_t reg; + + // Clear interrupts and enable them + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_TFR), SOC_DMA_CLEAR_CLEAR + (channel->id)); + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_BLOCK), SOC_DMA_CLEAR_CLEAR + (channel->id)); + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_ERR), SOC_DMA_CLEAR_CLEAR + (channel->id)); + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_TFR); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + SETB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_TFR) = reg; + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_BLOCK); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + SETB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_BLOCK) = reg; + + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_ERR); + SETB(reg, SOC_DMA_MASK_INT_MASK_WE + (channel->id)); + SETB(reg, SOC_DMA_MASK_INT_MASK + (channel->id)); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_MASK_ERR) = reg; + + SETB(dma_regs[channel->id].CTL_L, SOC_DMA_CTL_L_INT_EN); + + // Active channel + channel->active = 1; + SETB(dma_info->active, channel->id); + + // Turn on the given channel + reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CH_EN_REG); + SETB(reg, SOC_DMA_CH_EN_REG_CH_EN_WE + channel->id); + SETB(reg, SOC_DMA_CH_EN_REG_CH_EN + channel->id); + MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CH_EN_REG) = reg; + + return; +} + +static struct soc_dma_xfer_item *dma_find_list_end(struct soc_dma_xfer_item *head) +{ + struct soc_dma_xfer_item *t; + struct soc_dma_xfer_item *h; + + // Get rid of easy cases + if ((head == NULL) || (head->next == NULL) || + (head->next->next == NULL)) + { + return NULL; + } + + // Tortoise and hare check for cyclic ll + t = head->next; + h = head->next->next; + while (t != h) + { + h = h->next; + if (h == NULL) + { + return NULL; + } + h = h->next; + if (h == NULL) + { + return NULL; + } + t = t->next; + } + + // Find the meeting place since a cycle was detected + t = head; + while (t != h) + { + t = t->next; + h = h->next; + } + + return t; +} + +static struct dma_lli *dma_find_ll_end(struct dma_lli *head) +{ + struct dma_lli *t; + struct dma_lli *h; + + // Get rid of easy cases + if ((head == NULL) || (((struct dma_lli *)(head->llp)) == NULL) || + (((struct dma_lli *)(((struct dma_lli *)(head->llp))->llp)) == NULL)) + { + return NULL; + } + + // Tortoise and hare check for cyclic ll + t = (struct dma_lli *)(head->llp); + h = (struct dma_lli *)(((struct dma_lli *)(head->llp))->llp); + while (t != h) + { + h = (struct dma_lli *)(h->llp); + if (h == NULL) + { + return NULL; + } + h = (struct dma_lli *)(h->llp); + if (h == NULL) + { + return NULL; + } + t = (struct dma_lli *)(t->llp); + } + + // Find the meeting place since a cycle was detected + t = head; + while (t != h) + { + t = (struct dma_lli *)(t->llp); + h = (struct dma_lli *)(h->llp); + } + + return t; +} + +static DRIVER_API_RC dma_create_ll(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg) +{ + OS_ERR_TYPE err; + struct dma_lli *lli; + struct dma_lli *last_lli; + struct soc_dma_xfer_item *xfer; + struct soc_dma_xfer_item *last_xfer; + uint8_t list_done; + uint16_t size_left; + uint32_t curr_src; + uint8_t src_delta_amount; + uint32_t curr_dest; + uint8_t dest_delta_amount; + uint32_t reg; + + // Save the LL + channel->ll = balloc(sizeof(struct dma_lli), &err); + lli = (struct dma_lli *)(channel->ll); + last_lli = NULL; + + if (channel->ll == NULL) + { + return DRV_RC_FAIL; + } + + xfer = &(cfg->xfer); + last_xfer = dma_find_list_end(xfer); + + list_done = 0; + + // Set register to default CTL_L register value + reg = 0; + SETB(reg, SOC_DMA_CTL_L_LLP_SRC_EN); + SETB(reg, SOC_DMA_CTL_L_LLP_DST_EN); + SETV(reg, SOC_DMA_CTL_L_TT_FC, SOC_DMA_CTL_L_TT_FC_LEN, cfg->type); + SETV(reg, SOC_DMA_CTL_L_SRC_TR_WIDTH, SOC_DMA_CTL_L_SRC_TR_WIDTH_LEN, SOC_DMA_WIDTH_32); + SETV(reg, SOC_DMA_CTL_L_DST_TR_WIDTH, SOC_DMA_CTL_L_DST_TR_WIDTH_LEN, SOC_DMA_WIDTH_32); + SETB(reg, SOC_DMA_CTL_L_INT_EN); + + while (!list_done) + { + size_left = xfer->size; + curr_src = (uint32_t)(xfer->src.addr); + curr_dest = (uint32_t)(xfer->dest.addr); + + if (xfer == last_xfer) + { + last_lli = lli; + } + + while (size_left) + { + lli->sar = curr_src; + lli->dar = curr_dest; + + // Set the control register for this block + SETV(lli->ctl_u, SOC_DMA_CTL_U_BLOCK_TS, SOC_DMA_CTL_U_BLOCK_TS_LEN, + (size_left > SOC_DMA_BLOCK_SIZE_MAX) ? SOC_DMA_BLOCK_SIZE_MAX : size_left); + + lli->ctl_l = reg; + + if (cfg->src_step_count) + { + SETB(lli->ctl_l, SOC_DMA_CTL_L_SRC_GATHER_EN); + + // Scatter-Gather adds too much complexity for breaking up big blocks + if (size_left > SOC_DMA_BLOCK_SIZE_MAX) + { + soc_dma_deconfig(channel); + return DRV_RC_INVALID_CONFIG; + } + } + + if (cfg->dest_step_count) + { + SETB(lli->ctl_l, SOC_DMA_CTL_L_DST_SCATTER_EN); + + // Scatter-Gather adds too much complexity for breaking up big blocks + if (size_left > SOC_DMA_BLOCK_SIZE_MAX) + { + soc_dma_deconfig(channel); + return DRV_RC_INVALID_CONFIG; + } + } + + SETV(lli->ctl_l, SOC_DMA_CTL_L_SINC, SOC_DMA_CTL_L_SINC_LEN, xfer->src.delta); + SETV(lli->ctl_l, SOC_DMA_CTL_L_DINC, SOC_DMA_CTL_L_DINC_LEN, xfer->dest.delta); + + SETV(lli->ctl_l, SOC_DMA_CTL_L_SRC_TR_WIDTH, SOC_DMA_CTL_L_SRC_TR_WIDTH_LEN, xfer->src.width); + SETV(lli->ctl_l, SOC_DMA_CTL_L_DST_TR_WIDTH, SOC_DMA_CTL_L_DST_TR_WIDTH_LEN, xfer->dest.width); + + if (size_left > SOC_DMA_BLOCK_SIZE_MAX) + { + lli->end_group = 0; + lli->llp = (uint32_t)balloc(sizeof(struct dma_lli), &err); + + if (lli->llp == 0) + { + soc_dma_deconfig(channel); + return DRV_RC_FAIL; + } + + // Calculate new addresses for next block + size_left -= SOC_DMA_BLOCK_SIZE_MAX; + + src_delta_amount = ((xfer->src.width == SOC_DMA_WIDTH_8) ? 1 : + ((xfer->src.width == SOC_DMA_WIDTH_16) ? 2 : 4)); + dest_delta_amount = ((xfer->dest.width == SOC_DMA_WIDTH_8) ? 1 : + ((xfer->dest.width == SOC_DMA_WIDTH_16) ? 2 : 4)); + + switch (xfer->src.delta) + { + case SOC_DMA_DELTA_INCR: + curr_src += (src_delta_amount * SOC_DMA_BLOCK_SIZE_MAX); + break; + case SOC_DMA_DELTA_DECR: + curr_src -= (src_delta_amount * SOC_DMA_BLOCK_SIZE_MAX); + break; + } + + switch (xfer->dest.delta) + { + case SOC_DMA_DELTA_INCR: + curr_dest += (dest_delta_amount * SOC_DMA_BLOCK_SIZE_MAX); + break; + case SOC_DMA_DELTA_DECR: + curr_dest -= (dest_delta_amount * SOC_DMA_BLOCK_SIZE_MAX); + break; + } + + lli = (struct dma_lli *)lli->llp; + } + else + { + // Terminate this group of blocks for this xfer item + lli->end_group = 1; + size_left = 0; + } + } + + // Are we on the last block? If so, complete the list and leave, else setup the next loop + if ((xfer->next) == last_xfer) + { + lli->llp = (uint32_t)last_lli; + list_done = 1; + + if (lli->llp == 0) + { + SETB(lli->ctl_u, SOC_DMA_CTL_U_DONE_BIT); + CLRB(lli->ctl_l, SOC_DMA_CTL_L_LLP_SRC_EN); + CLRB(lli->ctl_l, SOC_DMA_CTL_L_LLP_DST_EN); + } + } + else + { + lli->llp = (uint32_t)balloc(sizeof(struct dma_lli), &err); + + if (lli->llp == 0) + { + soc_dma_deconfig(channel); + return DRV_RC_FAIL; + } + + xfer = xfer->next; + lli = (struct dma_lli *)lli->llp; + } + } + + return DRV_RC_OK; +} + +/* ISR */ +static void dma_interrupt_handler(void *num) +{ + uint32_t id = (uint32_t)num; + struct dma_lli *curr = ((struct dma_lli *)(dma_info->channel[id]->curr)); + + // Figure out whether this was a block or done interrupt + if (MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_STATUS_TFR) & (1 << (SOC_DMA_STATUS_STATUS + id))) + { + if ((dma_info->channel[id]) && (dma_info->channel[id]->cfg.cb_done)) + { + dma_info->channel[id]->cfg.cb_done(dma_info->channel[id]->cfg.cb_done_arg); + } + + // The user's callback might have already released the channel + if (dma_info->channel[id]) + { + dma_disable(dma_info->channel[id]); + } + } + else if (MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_STATUS_BLOCK) & (1 << (SOC_DMA_STATUS_STATUS + id))) + { + if ((dma_info->channel[id]) && (dma_info->channel[id]->cfg.cb_block) && (curr->end_group)) + { + dma_info->channel[id]->cfg.cb_block(dma_info->channel[id]->cfg.cb_block_arg); + } + + if (dma_info->channel[id]) + { + dma_info->channel[id]->curr = ((void *)(curr->llp)); + SETB_NR(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_CLEAR_BLOCK), SOC_DMA_CLEAR_CLEAR + id); + } + } + + return; +} + +DECLARE_INTERRUPT_HANDLER static void dma_interrupt_err_handler() +{ + uint32_t reg = MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_STATUS_ERR); + + // Loop through channels and see which have errors; calling callback and disabling + for (int i = 0; i < SOC_DMA_NUM_CHANNELS; i++) + { + if (reg & (1 << (SOC_DMA_STATUS_STATUS + i))) + { + if ((dma_info->channel[i]) && (dma_info->channel[i]->cfg.cb_err)) + { + dma_info->channel[i]->cfg.cb_err(dma_info->channel[i]->cfg.cb_err_arg); + } + + if (dma_info->channel[i]) + { + dma_disable(dma_info->channel[i]); + } + } + } + + return; +} + +/* External API */ +DRIVER_API_RC soc_dma_config(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg) +{ + DRIVER_API_RC ret; + uint32_t id = channel->id; + + // Check channel to be sure its alright to configure + if (channel == NULL) + { + return DRV_RC_FAIL; + } + else if (channel->active) + { + return DRV_RC_CONTROLLER_IN_USE; + } + + // Setup the config register + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_RELOAD_DST); + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_RELOAD_SRC); + + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_SRC_HS_POL); + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_DST_HS_POL); + + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_HS_SEL_SRC); + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_L), SOC_DMA_CFG_L_HS_SEL_DST); + + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), + SOC_DMA_CFG_U_DEST_PER, SOC_DMA_CFG_U_DEST_PER_LEN, cfg->dest_interface); + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), + SOC_DMA_CFG_U_SRC_PER, SOC_DMA_CFG_U_SRC_PER_LEN, cfg->src_interface); + + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_SS_UPD_EN); + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_DS_UPD_EN); + + SETB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_FIFO_MODE); + CLRB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].CFG_U), SOC_DMA_CFG_U_FCMODE); + + // Create new LL for DMA transfer + ret = dma_create_ll(channel, cfg); + + if (ret != DRV_RC_OK) + { + return ret; + } + + // Setup scatter-gather registers + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].SGR), + SOC_DMA_SGR_SGC, SOC_DMA_SGR_SGC_LEN, cfg->src_step_count); + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].SGR), + SOC_DMA_SGR_SGI, SOC_DMA_SGR_SGI_LEN, cfg->src_step_interval); + + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].DSR), + SOC_DMA_DSR_DSC, SOC_DMA_DSR_DSC_LEN, cfg->dest_step_count); + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[id].DSR), + SOC_DMA_DSR_DSI, SOC_DMA_DSR_DSI_LEN, cfg->dest_step_interval); + + // Setup the channel structs cfg stuff + channel->cfgd = 1; + channel->cfg = *cfg; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_deconfig(struct soc_dma_channel *channel) +{ + struct dma_lli *lli; + struct dma_lli *lli_next; + struct dma_lli *last_lli; + + // Check channel to be sure its alright to deconfigure + if (channel == NULL) + { + return DRV_RC_FAIL; + } + else if (channel->active) + { + return DRV_RC_CONTROLLER_IN_USE; + } + + // Free the link list + lli = (struct dma_lli *)(channel->ll); + last_lli = dma_find_ll_end(lli); + + while (lli) + { + if (((struct dma_lli *)(lli->llp)) == last_lli) + { + bfree(lli); + lli = NULL; + } + else + { + lli_next = ((struct dma_lli *)(lli->llp)); + bfree(lli); + lli = lli_next; + } + } + + channel->ll = NULL; + + channel->cfgd = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_acquire(struct soc_dma_channel *channel) +{ + uint32_t save; + + // Get a channel from the semaphore if one is free + save = interrupt_lock(); + + // Find the first free channel and set it up in the given struct + for (int i = 0; i < SOC_DMA_NUM_CHANNELS; i++) + { + if (dma_info->channel[i] == NULL) + { + dma_info->channel[i] = channel; + channel->id = i; + channel->active = 0; + soc_dma_deconfig(channel); + interrupt_unlock(save); + return DRV_RC_OK; + } + } + + // Somehow, we got an item from the semaphore but found no free channels... + interrupt_unlock(save); + + return DRV_RC_FAIL; +} + +DRIVER_API_RC soc_dma_release(struct soc_dma_channel *channel) +{ + + if (channel->active) + { + return DRV_RC_CONTROLLER_IN_USE; + } + + // Deconfig the channel if still configured + if (channel->cfgd) + { + soc_dma_deconfig(channel); + } + + // Clear the channel + dma_info->channel[channel->id] = NULL; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_start_transfer(struct soc_dma_channel *channel) +{ + uint32_t save; + + if (!channel->cfgd) + { + return DRV_RC_FAIL; + } + + // Setup the control register for first "transfer" + SETB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[channel->id].CTL_L), SOC_DMA_CTL_L_LLP_SRC_EN); + SETB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[channel->id].CTL_L), SOC_DMA_CTL_L_LLP_DST_EN); + + SETB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[channel->id].CTL_L), SOC_DMA_CTL_L_INT_EN); + + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[channel->id].CTL_L), + SOC_DMA_CTL_L_TT_FC, SOC_DMA_CTL_L_TT_FC_LEN, channel->cfg.type); + + // Setup LLP register to point to first block + SETV(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, dma_regs[channel->id].LLP), + SOC_DMA_LLP_LOC, SOC_DMA_LLP_LOC_LEN, ((uint32_t)(channel->ll)) >> SOC_DMA_LLP_LOC); + + // Set the current LLI pointer to point at the head of the list + channel->curr = channel->ll; + + save = interrupt_lock(); + dma_enable(channel); + interrupt_unlock(save); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_stop_transfer(struct soc_dma_channel *channel) +{ + uint32_t save; + + save = interrupt_lock(); + dma_disable(channel); + interrupt_unlock(save); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_alloc_list_item(struct soc_dma_xfer_item **ret, struct soc_dma_xfer_item *base) +{ + OS_ERR_TYPE err; + + *ret = balloc(sizeof(struct soc_dma_xfer_item), &err); + + if (*ret == NULL) + { + *ret = NULL; + return DRV_RC_FAIL; + } + + // Copy and connect to the base if one is given + if (base) + { + **ret = *base; + base->next = (*ret); + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_dma_free_list(struct soc_dma_cfg *cfg) +{ + struct soc_dma_xfer_item *p; + struct soc_dma_xfer_item *np; + struct soc_dma_xfer_item *lp; + + p = cfg->xfer.next; + lp = dma_find_list_end(&(cfg->xfer)); + + while (p) + { + if (p->next == lp) + { + bfree(p); + p = NULL; + } + else + { + np = p->next; + bfree(p); + p = np; + } + } + + cfg->xfer.next = NULL; + + return DRV_RC_OK; +} + +/* Driver API */ +DRIVER_API_RC soc_dma_init() +{ + struct soc_dma_channel ch; + + dma_info->active = 0; + + // Enable global clock + SETB(MMIO_REG_VAL(MLAYER_AHB_CTL), 6); + + // Setup ISRs (and enable) + for (int i = 0; i < SOC_DMA_NUM_CHANNELS; i++) + { + SET_INTERRUPT_HANDLER(dma_info->int_vector[i], dma_info->int_handler[i]); + SOC_UNMASK_INTERRUPTS(dma_info->int_mask[i]); + } + SET_INTERRUPT_HANDLER(dma_info->err_vector, &dma_interrupt_err_handler); + SOC_UNMASK_INTERRUPTS(dma_info->err_mask); + + // Setup global DMA registers settings + SETB(MMIO_REG_VAL_FROM_BASE(SOC_DMA_BASE, SOC_DMA_DMA_CFG_REG), SOC_DMA_DMA_CFG_REG_DMA_EN); + + // Disable all channels for now and leave the channel array empty + for (int i = 0; i < SOC_DMA_NUM_CHANNELS; i++) + { + ch.id = i; + dma_disable(&ch); + dma_info->channel[i] = NULL; + } + + return DRV_RC_OK; +} + diff --git a/system/libarc32_arduino101/drivers/soc_dma.h b/system/libarc32_arduino101/drivers/soc_dma.h new file mode 100644 index 00000000..e81d071b --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_dma.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_DMA_H_ +#define SOC_DMA_H_ + +#include "data_type.h" +#include "os/os.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SOC_DMA_NUM_CHANNELS 8 + +// Valid values for type +#define SOC_DMA_TYPE_MEM2MEM 0 +#define SOC_DMA_TYPE_MEM2PER 1 +#define SOC_DMA_TYPE_PER2MEM 2 +#define SOC_DMA_TYPE_PER2PER 3 + +// Valid values for delta +#define SOC_DMA_DELTA_INCR 0 +#define SOC_DMA_DELTA_DECR 1 +#define SOC_DMA_DELTA_NONE 2 + +// Valid values for width +#define SOC_DMA_WIDTH_8 0 +#define SOC_DMA_WIDTH_16 1 +#define SOC_DMA_WIDTH_32 2 + +// Valid values for dest_interface or src_interface +#define SOC_DMA_INTERFACE_UART0_TX 0 +#define SOC_DMA_INTERFACE_UART0_RX 1 +#define SOC_DMA_INTERFACE_UART1_TX 2 +#define SOC_DMA_INTERFACE_UART1_RX 3 +#define SOC_DMA_INTERFACE_SPIM0_TX 4 +#define SOC_DMA_INTERFACE_SPIM0_RX 5 +#define SOC_DMA_INTERFACE_SPIM1_TX 6 +#define SOC_DMA_INTERFACE_SPIM1_RX 7 +#define SOC_DMA_INTERFACE_SPIS_TX 8 +#define SOC_DMA_INTERFACE_SPIS_RX 9 +#define SOC_DMA_INTERFACE_I2S_TX 10 +#define SOC_DMA_INTERFACE_I2S_RX 11 +#define SOC_DMA_INTERFACE_I2C0_TX 12 +#define SOC_DMA_INTERFACE_I2C0_RX 13 +#define SOC_DMA_INTERFACE_I2C1_TX 14 +#define SOC_DMA_INTERFACE_I2C1_RX 15 + +// Part of the list item that is the same from destination and source +struct soc_dma_xfer_part { + uint8_t delta; + uint8_t width; + void *addr; +}; + +// DMa transfer list item +struct soc_dma_xfer_item { + struct soc_dma_xfer_part src; + struct soc_dma_xfer_part dest; + struct soc_dma_xfer_item *next; + uint16_t size; +}; + +// DMA configuration object +struct soc_dma_cfg { + uint8_t type; + + uint8_t dest_interface; + uint8_t src_interface; + uint8_t dest_step_count; + uint8_t src_step_count; + uint32_t dest_step_interval; + uint32_t src_step_interval; + + struct soc_dma_xfer_item xfer; + + void (*cb_done)(void *); + void (*cb_block)(void *); + void (*cb_err)(void *); + void *cb_done_arg; + void *cb_block_arg; + void *cb_err_arg; +}; + +// DMA channel object +struct soc_dma_channel { + uint8_t id; + uint8_t active; + uint8_t cfgd; + struct soc_dma_cfg cfg; + void *ll; + void *curr; +}; + +typedef void (*isr_func)(void); + +// Internal struct for use by the controller (and soc_config) +struct soc_dma_info { + uint32_t int_mask[SOC_DMA_NUM_CHANNELS]; + uint32_t int_vector[SOC_DMA_NUM_CHANNELS]; + isr_func int_handler[SOC_DMA_NUM_CHANNELS]; + uint32_t err_mask; + uint32_t err_vector; + + struct soc_dma_channel* channel[SOC_DMA_NUM_CHANNELS]; + + uint32_t active; +}; + + +/** + * Function to configure a DMA channel (and set it up for transfer) + * + * @param channel : pointer to channel object + * @param cfg : pointer to configuration by which to configure the channel + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_INVALID_CONFIG - if any configuration parameters are not valid + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_config(struct soc_dma_channel *channel, struct soc_dma_cfg *cfg); + +/** + * Function to deconfigure and disable a DMA channel + * + * @param channel : pointer to channel object + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_deconfig(struct soc_dma_channel *channel); + +/** + * Function to acquire a free DMA channel, must be called before any other DMA functions are used + * + * @param channel : pointer to channel object + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_acquire(struct soc_dma_channel *channel); + +/** + * Function to release a held DMA channel so it can be used by others + * + * @param channel : pointer to channel object + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_release(struct soc_dma_channel *channel); + +/** + * Function to start a DMA transfer, the channel must be configured before this function is called + * + * @param channel : pointer to channel object + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_start_transfer(struct soc_dma_channel *channel); + +/** + * Function to stop an ongoing DMA channel, does nothing if no transfer is in progress + * + * @param channel : pointer to channel object + * + * @return + * - DRV_RC_OK on success + */ +DRIVER_API_RC soc_dma_stop_transfer(struct soc_dma_channel *channel); + +/** + * Function to create a new node for a DMA xfer list. If base is provided, the allocated item will + * inherit all the fields from base and the new item will be linked as the item after base + * + * @param ret : pointer to pointer which will be assigned to the new list item + * @param base : pointer to list item to be used as a base + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_dma_alloc_list_item(struct soc_dma_xfer_item **ret, struct soc_dma_xfer_item *base); + +/** + * Function to free a DMA xfer list (given in the configuration object), should only be used if the + * list was allocated with soc_dma_alloc_list_item + * + * @param cfg : pointer to configuration object + * + * @return + * - DRV_RC_OK on success + */ +DRIVER_API_RC soc_dma_free_list(struct soc_dma_cfg *cfg); + +DRIVER_API_RC soc_dma_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_DMA_H_ */ diff --git a/system/libarc32_arduino101/drivers/soc_dma_priv.h b/system/libarc32_arduino101/drivers/soc_dma_priv.h new file mode 100644 index 00000000..5497e3a0 --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_dma_priv.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_DMA_PRIV_H_ +#define SOC_DMA_PRIV_H_ + +#include "soc_dma.h" + +// Timeout on acquiring the DMA semaphore +#define SOC_DMA_SEMAPHORE_DELAY 1000 + +// Largest size a single DMA transfer can be (limited by BLOCK_TS bits in CTL_H) +#define SOC_DMA_BLOCK_SIZE_MAX 4095 + +// DMA Register map and fields +#define SOC_DMA_SAR_0 (0x000) +#define SOC_DMA_SAR_1 (0x058) +#define SOC_DMA_SAR_2 (0x0B0) +#define SOC_DMA_SAR_3 (0x108) +#define SOC_DMA_SAR_4 (0x160) +#define SOC_DMA_SAR_5 (0x1B8) +#define SOC_DMA_SAR_6 (0x210) +#define SOC_DMA_SAR_7 (0x268) +#define SOC_DMA_SAR_SAR (0) +#define SOC_DMA_SAR_SAR_LEN (32) + +#define SOC_DMA_DAR_0 (0x008) +#define SOC_DMA_DAR_1 (0x060) +#define SOC_DMA_DAR_2 (0x0B8) +#define SOC_DMA_DAR_3 (0x110) +#define SOC_DMA_DAR_4 (0x168) +#define SOC_DMA_DAR_5 (0x1C0) +#define SOC_DMA_DAR_6 (0x218) +#define SOC_DMA_DAR_7 (0x270) +#define SOC_DMA_DAR_DAR (0) +#define SOC_DMA_DAR_DAR_LEN (32) + +#define SOC_DMA_LLP_0 (0x010) +#define SOC_DMA_LLP_1 (0x068) +#define SOC_DMA_LLP_2 (0x0C0) +#define SOC_DMA_LLP_3 (0x118) +#define SOC_DMA_LLP_4 (0x170) +#define SOC_DMA_LLP_5 (0x1C8) +#define SOC_DMA_LLP_6 (0x220) +#define SOC_DMA_LLP_7 (0x278) +#define SOC_DMA_LLP_LOC (2) +#define SOC_DMA_LLP_LOC_LEN (30) + +#define SOC_DMA_CTL_L_0 (0x018) +#define SOC_DMA_CTL_L_1 (0x070) +#define SOC_DMA_CTL_L_2 (0x0C8) +#define SOC_DMA_CTL_L_3 (0x120) +#define SOC_DMA_CTL_L_4 (0x178) +#define SOC_DMA_CTL_L_5 (0x1D0) +#define SOC_DMA_CTL_L_6 (0x228) +#define SOC_DMA_CTL_L_7 (0x280) +#define SOC_DMA_CTL_L_LLP_SRC_EN (28) +#define SOC_DMA_CTL_L_LLP_DST_EN (27) +#define SOC_DMA_CTL_L_TT_FC (20) +#define SOC_DMA_CTL_L_TT_FC_LEN (3) +#define SOC_DMA_CTL_L_DST_SCATTER_EN (18) +#define SOC_DMA_CTL_L_SRC_GATHER_EN (17) +#define SOC_DMA_CTL_L_SRC_MSIZE (14) +#define SOC_DMA_CTL_L_SRC_MSIZE_LEN (3) +#define SOC_DMA_CTL_L_DEST_MSIZE (11) +#define SOC_DMA_CTL_L_DEST_MSIZE_LEN (3) +#define SOC_DMA_CTL_L_SINC (9) +#define SOC_DMA_CTL_L_SINC_LEN (2) +#define SOC_DMA_CTL_L_DINC (7) +#define SOC_DMA_CTL_L_DINC_LEN (2) +#define SOC_DMA_CTL_L_SRC_TR_WIDTH (4) +#define SOC_DMA_CTL_L_SRC_TR_WIDTH_LEN (3) +#define SOC_DMA_CTL_L_DST_TR_WIDTH (1) +#define SOC_DMA_CTL_L_DST_TR_WIDTH_LEN (3) +#define SOC_DMA_CTL_L_INT_EN (0) + +#define SOC_DMA_CTL_U_0 (0x01C) +#define SOC_DMA_CTL_U_1 (0x074) +#define SOC_DMA_CTL_U_2 (0x0CC) +#define SOC_DMA_CTL_U_3 (0x124) +#define SOC_DMA_CTL_U_4 (0x17C) +#define SOC_DMA_CTL_U_5 (0x1D4) +#define SOC_DMA_CTL_U_6 (0x22C) +#define SOC_DMA_CTL_U_7 (0x284) +#define SOC_DMA_CTL_U_DONE_BIT (12) +#define SOC_DMA_CTL_U_BLOCK_TS (0) +#define SOC_DMA_CTL_U_BLOCK_TS_LEN (12) + +#define SOC_DMA_CFG_L_0 (0x040) +#define SOC_DMA_CFG_L_1 (0x098) +#define SOC_DMA_CFG_L_2 (0x0F0) +#define SOC_DMA_CFG_L_3 (0x148) +#define SOC_DMA_CFG_L_4 (0x1A0) +#define SOC_DMA_CFG_L_5 (0x1F8) +#define SOC_DMA_CFG_L_6 (0x250) +#define SOC_DMA_CFG_L_7 (0x2A8) +#define SOC_DMA_CFG_L_RELOAD_DST (31) +#define SOC_DMA_CFG_L_RELOAD_SRC (30) +#define SOC_DMA_CFG_L_SRC_HS_POL (19) +#define SOC_DMA_CFG_L_DST_HS_POL (18) +#define SOC_DMA_CFG_L_HS_SEL_SRC (11) +#define SOC_DMA_CFG_L_HS_SEL_DST (10) +#define SOC_DMA_CFG_L_FIFO_EMPTY (9) +#define SOC_DMA_CFG_L_CH_SUSP (8) +#define SOC_DMA_CFG_L_CH_PRIOR (5) +#define SOC_DMA_CFG_L_CH_PRIOR_LEN (3) + +#define SOC_DMA_CFG_U_0 (0x044) +#define SOC_DMA_CFG_U_1 (0x09C) +#define SOC_DMA_CFG_U_2 (0x0F4) +#define SOC_DMA_CFG_U_3 (0x14C) +#define SOC_DMA_CFG_U_4 (0x1A4) +#define SOC_DMA_CFG_U_5 (0x1FC) +#define SOC_DMA_CFG_U_6 (0x254) +#define SOC_DMA_CFG_U_7 (0x2AC) +#define SOC_DMA_CFG_U_DEST_PER (11) +#define SOC_DMA_CFG_U_DEST_PER_LEN (4) +#define SOC_DMA_CFG_U_SRC_PER (7) +#define SOC_DMA_CFG_U_SRC_PER_LEN (4) +#define SOC_DMA_CFG_U_SS_UPD_EN (6) +#define SOC_DMA_CFG_U_DS_UPD_EN (5) +#define SOC_DMA_CFG_U_PROTCTL (2) +#define SOC_DMA_CFG_U_PROTCTL_LEN (3) +#define SOC_DMA_CFG_U_FIFO_MODE (1) +#define SOC_DMA_CFG_U_FCMODE (0) + +#define SOC_DMA_SGR_0 (0x048) +#define SOC_DMA_SGR_1 (0x0A0) +#define SOC_DMA_SGR_2 (0x0F8) +#define SOC_DMA_SGR_3 (0x150) +#define SOC_DMA_SGR_4 (0x1A8) +#define SOC_DMA_SGR_5 (0x200) +#define SOC_DMA_SGR_6 (0x258) +#define SOC_DMA_SGR_7 (0x2B0) +#define SOC_DMA_SGR_SGC (20) +#define SOC_DMA_SGR_SGC_LEN (5) +#define SOC_DMA_SGR_SGI (0) +#define SOC_DMA_SGR_SGI_LEN (20) + +#define SOC_DMA_DSR_0 (0x050) +#define SOC_DMA_DSR_1 (0x0A8) +#define SOC_DMA_DSR_2 (0x100) +#define SOC_DMA_DSR_3 (0x158) +#define SOC_DMA_DSR_4 (0x1B0) +#define SOC_DMA_DSR_5 (0x208) +#define SOC_DMA_DSR_6 (0x260) +#define SOC_DMA_DSR_7 (0x2B8) +#define SOC_DMA_DSR_DSC (20) +#define SOC_DMA_DSR_DSC_LEN (5) +#define SOC_DMA_DSR_DSI (0) +#define SOC_DMA_DSR_DSI_LEN (20) + +#define SOC_DMA_RAW_TFR (0x2C0) +#define SOC_DMA_RAW_BLOCK (0x2C8) +#define SOC_DMA_RAW_SRC_TRAN (0x2D0) +#define SOC_DMA_RAW_DST_TRAN (0x2D8) +#define SOC_DMA_RAW_ERR (0x2E0) +#define SOC_DMA_RAW_RAW (0) + +#define SOC_DMA_STATUS_TFR (0x2E8) +#define SOC_DMA_STATUS_BLOCK (0x2F0) +#define SOC_DMA_STATUS_SRC_TRAN (0x2F8) +#define SOC_DMA_STATUS_DST_TRAN (0x300) +#define SOC_DMA_STATUS_ERR (0x308) +#define SOC_DMA_STATUS_STATUS (0) + +#define SOC_DMA_MASK_TFR (0x310) +#define SOC_DMA_MASK_BLOCK (0x318) +#define SOC_DMA_MASK_SRC_TRAN (0x320) +#define SOC_DMA_MASK_DST_TRAN (0x328) +#define SOC_DMA_MASK_ERR (0x330) +#define SOC_DMA_MASK_INT_MASK_WE (8) +#define SOC_DMA_MASK_INT_MASK (0) + +#define SOC_DMA_CLEAR_TFR (0x338) +#define SOC_DMA_CLEAR_BLOCK (0x340) +#define SOC_DMA_CLEAR_SRC_TRAN (0x348) +#define SOC_DMA_CLEAR_DST_TRAN (0x350) +#define SOC_DMA_CLEAR_ERR (0x358) +#define SOC_DMA_CLEAR_CLEAR (0) + +#define SOC_DMA_DMA_CFG_REG (0x398) +#define SOC_DMA_DMA_CFG_REG_DMA_EN (0) + +#define SOC_DMA_CH_EN_REG (0x3A0) +#define SOC_DMA_CH_EN_REG_CH_EN_WE (8) +#define SOC_DMA_CH_EN_REG_CH_EN (0) + +// DMA Register map struct, used to refer to a channel's specific registers by base name and id number +struct dma_reg_map { + uint16_t SAR; + uint16_t DAR; + + uint16_t LLP; + + uint16_t CTL_L; + + uint16_t CTL_U; + + uint16_t CFG_L; + + uint16_t CFG_U; + + uint16_t SGR; + + uint16_t DSR; +}; + +struct dma_reg_map dma_regs[SOC_DMA_NUM_CHANNELS] = { + { + .SAR = SOC_DMA_SAR_0, + .DAR = SOC_DMA_DAR_0, + .LLP = SOC_DMA_LLP_0, + .CTL_L = SOC_DMA_CTL_L_0, + .CTL_U = SOC_DMA_CTL_U_0, + .CFG_L = SOC_DMA_CFG_L_0, + .CFG_U = SOC_DMA_CFG_U_0, + .SGR = SOC_DMA_SGR_0, + .DSR = SOC_DMA_DSR_0 + }, + { + .SAR = SOC_DMA_SAR_1, + .DAR = SOC_DMA_DAR_1, + .LLP = SOC_DMA_LLP_1, + .CTL_L = SOC_DMA_CTL_L_1, + .CTL_U = SOC_DMA_CTL_U_1, + .CFG_L = SOC_DMA_CFG_L_1, + .CFG_U = SOC_DMA_CFG_U_1, + .SGR = SOC_DMA_SGR_1, + .DSR = SOC_DMA_DSR_1 + }, + { + .SAR = SOC_DMA_SAR_2, + .DAR = SOC_DMA_DAR_2, + .LLP = SOC_DMA_LLP_2, + .CTL_L = SOC_DMA_CTL_L_2, + .CTL_U = SOC_DMA_CTL_U_2, + .CFG_L = SOC_DMA_CFG_L_2, + .CFG_U = SOC_DMA_CFG_U_2, + .SGR = SOC_DMA_SGR_2, + .DSR = SOC_DMA_DSR_2 + }, + { + .SAR = SOC_DMA_SAR_3, + .DAR = SOC_DMA_DAR_3, + .LLP = SOC_DMA_LLP_3, + .CTL_L = SOC_DMA_CTL_L_3, + .CTL_U = SOC_DMA_CTL_U_3, + .CFG_L = SOC_DMA_CFG_L_3, + .CFG_U = SOC_DMA_CFG_U_3, + .SGR = SOC_DMA_SGR_3, + .DSR = SOC_DMA_DSR_3 + }, + { + .SAR = SOC_DMA_SAR_4, + .DAR = SOC_DMA_DAR_4, + .LLP = SOC_DMA_LLP_4, + .CTL_L = SOC_DMA_CTL_L_4, + .CTL_U = SOC_DMA_CTL_U_4, + .CFG_L = SOC_DMA_CFG_L_4, + .CFG_U = SOC_DMA_CFG_U_4, + .SGR = SOC_DMA_SGR_4, + .DSR = SOC_DMA_DSR_4 + }, + { + .SAR = SOC_DMA_SAR_5, + .DAR = SOC_DMA_DAR_5, + .LLP = SOC_DMA_LLP_5, + .CTL_L = SOC_DMA_CTL_L_5, + .CTL_U = SOC_DMA_CTL_U_5, + .CFG_L = SOC_DMA_CFG_L_5, + .CFG_U = SOC_DMA_CFG_U_5, + .SGR = SOC_DMA_SGR_5, + .DSR = SOC_DMA_DSR_5 + }, + { + .SAR = SOC_DMA_SAR_6, + .DAR = SOC_DMA_DAR_6, + .LLP = SOC_DMA_LLP_6, + .CTL_L = SOC_DMA_CTL_L_6, + .CTL_U = SOC_DMA_CTL_U_6, + .CFG_L = SOC_DMA_CFG_L_6, + .CFG_U = SOC_DMA_CFG_U_6, + .SGR = SOC_DMA_SGR_6, + .DSR = SOC_DMA_DSR_6 + }, + { + .SAR = SOC_DMA_SAR_7, + .DAR = SOC_DMA_DAR_7, + .LLP = SOC_DMA_LLP_7, + .CTL_L = SOC_DMA_CTL_L_7, + .CTL_U = SOC_DMA_CTL_U_7, + .CFG_L = SOC_DMA_CFG_L_7, + .CFG_U = SOC_DMA_CFG_U_7, + .SGR = SOC_DMA_SGR_7, + .DSR = SOC_DMA_DSR_7 + } +}; + +// DMA Link List Item as specified by the DW DMAC doc; end_group is special field used by controller +struct dma_lli { + uint32_t sar; + uint32_t dar; + uint32_t llp; + uint32_t ctl_l; + uint32_t ctl_u; + uint32_t dstat; + uint32_t sstat; + uint8_t end_group; +}; + +#endif /* SOC_DMA_PRIV_H_ */ diff --git a/system/libarc32_arduino101/drivers/soc_i2s.c b/system/libarc32_arduino101/drivers/soc_i2s.c new file mode 100644 index 00000000..70b51429 --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_i2s.c @@ -0,0 +1,672 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "scss_registers.h" +#include "portable.h" +#include "os/os.h" +#include "i2s_priv.h" +#include "data_type.h" +#include "clk_system.h" +#include "soc_i2s.h" + +/* Info struct */ +struct soc_i2s_info g_i2s_info = { + .reg_base = SOC_I2S_BASE, + .int_vector = SOC_I2S_INTERRUPT, + .int_mask = INT_I2S_MASK, + .clk_speed = 32000000, + .clk_gate_info = &(struct clk_gate_info_s) + { + .clk_gate_register = PERIPH_CLK_GATE_CTRL, + .bits_mask = I2S_CLK_GATE_MASK, + } +}; + +struct soc_i2s_info* i2s_info = &g_i2s_info; + +/* Function Prototypes */ +static void i2s_enable(uint8_t channel); +static void i2s_disable(uint8_t channel); +static void i2s_isr(void); +DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg); +DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); +DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len); +DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs); +DRIVER_API_RC soc_i2s_stop_listen(void); +DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len); +DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs); +DRIVER_API_RC soc_i2s_stop_stream(void); +DRIVER_API_RC soc_i2s_init(); + +/* Internal functions */ +static void i2s_enable(uint8_t channel) +{ + uint32_t reg; + + // Enable local clock and interrupts + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].cid_ctrl); + reg &= ~(1 << (i2s_reg_map[channel].cid_ctrl_strobe)); + reg &= ~(1 << (i2s_reg_map[channel].cid_ctrl_strobe_sync)); + reg |= (1 << (i2s_reg_map[channel].cid_ctrl_mask)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].cid_ctrl) = reg; + + // Clear all interrupts + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].stat); + reg &= ~(i2s_reg_map[channel].stat_mask); + reg |= (1 << SOC_I2S_STAT_TDATA_UNDERR); + reg |= (1 << SOC_I2S_STAT_RDATA_OVRERR); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].stat) = reg; + + // Set enabled flag for channel + i2s_info->en[channel] = 1; + + return; +} + +static void i2s_disable(uint8_t channel) +{ + uint32_t reg; + uint32_t num_active; + int i; + + // Release DMA resources + if (i2s_info->en[channel]) + { + soc_dma_stop_transfer(&(i2s_info->dma_ch[channel])); + soc_dma_release(&(i2s_info->dma_ch[channel])); + soc_dma_free_list(&(i2s_info->dma_cfg[channel])); + } + // Clear enabled flag for channel + i2s_info->en[channel] = 0; + + // Let the processor do whatever power down it wants + num_active = 0; + for (i = 0; i < I2S_NUM_CHANNELS; i++) + { + if (i2s_info->en[i]) + { + num_active++; + } + } + + // Disable channel and hold parts in reset + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); + reg &= ~(1 << (i2s_reg_map[channel].ctrl_fifo_rst)); + reg &= ~(1 << (i2s_reg_map[channel].ctrl_sync_rst)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; + + // Clear all interrupts + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].stat); + reg &= ~(i2s_reg_map[channel].stat_mask); + reg &= ~(1 << i2s_reg_map[channel].stat_err); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].stat) = reg; + + // Disable local clock and interrupts + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].cid_ctrl); + reg |= (1 << (i2s_reg_map[channel].cid_ctrl_strobe)); + reg |= (1 << (i2s_reg_map[channel].cid_ctrl_strobe_sync)); + reg &= ~(1 << (i2s_reg_map[channel].cid_ctrl_mask)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].cid_ctrl) = reg; + + return; + +} + +/* ISR */ +static void i2s_isr(void) +{ + uint32_t stat; + + // Determine interrupt source + stat = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_STAT); + + // Check for errors + if (stat & (1 << SOC_I2S_STAT_TDATA_UNDERR)) + { + if (i2s_info->cfg[I2S_CHANNEL_TX].cb_err) + { + i2s_info->cfg[I2S_CHANNEL_TX].cb_err_arg=(void *)stat; + i2s_info->cfg[I2S_CHANNEL_TX].cb_err(i2s_info->cfg[I2S_CHANNEL_TX].cb_err_arg); + } + i2s_disable(I2S_CHANNEL_TX); + } + if (stat & (1 << SOC_I2S_STAT_RDATA_OVRERR)) + { + if (i2s_info->cfg[I2S_CHANNEL_RX].cb_err) + { + i2s_info->cfg[I2S_CHANNEL_RX].cb_err_arg=(void *)stat; + i2s_info->cfg[I2S_CHANNEL_RX].cb_err(i2s_info->cfg[I2S_CHANNEL_RX].cb_err_arg); + } + i2s_disable(I2S_CHANNEL_RX); + } + + return; +} + +DECLARE_INTERRUPT_HANDLER static void i2s_interrupt_handler() +{ + i2s_isr(); +} + +/* DMA Callbacks */ +static void i2s_dma_cb_err(void *num) +{ + uint8_t channel = (uint32_t)num; + + if (i2s_info->cfg[channel].cb_err) + { + i2s_info->cfg[channel].cb_err(i2s_info->cfg[channel].cb_err_arg); + } + i2s_disable(channel); + + return; +} + +static void i2s_dma_cb_done(void *num) +{ + uint8_t channel = (uint32_t)num; + uint32_t reg; + + if(channel == I2S_CHANNEL_TX) + { + if((0x00200000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL)) + && !(0x18000000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL))) + { + for(int i = 0; i < 4; ++i) + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_DATA_REG) = 0x0; + } + + do + { + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].fifo_stat); + } while(reg & 0x000000FF); + } + + if (i2s_info->cfg[channel].cb_done) + { + i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg); + } + + i2s_disable(channel); + + return; +} + +static void i2s_dma_cb_block(void *num) +{ + uint8_t channel = (uint32_t)num; + + if (i2s_info->cfg[channel].cb_done) + { + i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg); + } + + return; +} + +/* External API */ +DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg) +{ + uint32_t reg; + uint16_t sample_rate; + + // Check channel no in use + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (i2s_info->en[channel]) + { + return DRV_RC_CONTROLLER_IN_USE; + } + + // Set master/slave + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); + reg &= ~(1 << (i2s_reg_map[channel].ctrl_ms)); + reg |= (cfg->master & 0x1) << i2s_reg_map[channel].ctrl_ms; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; + + // Calculate sample_rate divider (note, acts as if resolution is always 32) + sample_rate = i2s_info->clk_speed / (cfg->sample_rate * cfg->resolution * 2); + + // Setup resolution and sampling rate + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].srr); + reg &= ~(i2s_reg_map[channel].srr_mask); + reg |= (sample_rate & 0x7FF) << i2s_reg_map[channel].srr_sample_rate; + reg |= ((cfg->resolution - 1) & 0x1F) << i2s_reg_map[channel].srr_resolution; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].srr) = reg; + + // Setup mode + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].dev_conf); + reg &= ~(i2s_reg_map[channel].dev_conf_mask); + // Use sck_polar as shift amount as its the LSb of the DEV_CONF settings + reg |= ((cfg->mode & 0x3F) << i2s_reg_map[channel].dev_conf_sck_polar); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].dev_conf) = reg; + + // Complete configuration (and set flag) + i2s_info->cfg[channel] = *cfg; + i2s_info->cfgd[channel] = 1; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2s_deconfig(uint8_t channel) +{ + // Check channel no in use + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (i2s_info->en[channel]) + { + return DRV_RC_CONTROLLER_IN_USE; + } + + i2s_info->cfgd[channel] = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len) +{ + // Calling listen with 0 buffers is the same as a onetime read of the whole buffer + return soc_i2s_listen(buf, len, 0); +} + +DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs) +{ + DRIVER_API_RC ret; + uint8_t channel = I2S_CHANNEL_RX; + uint32_t reg; + uint32_t len_per_buf; + int i; + struct soc_dma_xfer_item *dma_list; + + // Check channel no in use and configured + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (i2s_info->en[channel] || !(i2s_info->cfgd[channel])) + { + return DRV_RC_FAIL; + } + + // Get a DMA channel + ret = soc_dma_acquire(&(i2s_info->dma_ch[channel])); + + if (ret != DRV_RC_OK) + { + return DRV_RC_FAIL; + } + + // Enable the channel + i2s_enable(channel); + + // Determine the length of a single buffer + if (num_bufs == 0) + { + len_per_buf = len; + } + else + { + len_per_buf = len / num_bufs; + } + + // Prep some configuration + i2s_info->dma_cfg[channel].type = SOC_DMA_TYPE_PER2MEM; + i2s_info->dma_cfg[channel].src_interface = SOC_DMA_INTERFACE_I2S_RX; + i2s_info->dma_cfg[channel].dest_step_count = 0; + i2s_info->dma_cfg[channel].src_step_count = 0; + + i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_INCR; + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_NONE; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[channel].xfer.src.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); + + if (num_bufs == 0) + { + i2s_info->dma_cfg[channel].cb_done = i2s_dma_cb_done; + i2s_info->dma_cfg[channel].cb_done_arg = (void *)((uint32_t)channel); + } + else + { + i2s_info->dma_cfg[channel].cb_block = i2s_dma_cb_block; + i2s_info->dma_cfg[channel].cb_block_arg = (void *)((uint32_t)channel); + } + + i2s_info->dma_cfg[channel].cb_err = i2s_dma_cb_err; + i2s_info->dma_cfg[channel].cb_err_arg = (void *)((uint32_t)channel); + + // Setup the linked list + for (i = 0; i < ((num_bufs == 0) ? 1 : num_bufs); i++) + { + if (i == 0) + { + dma_list = &(i2s_info->dma_cfg[channel].xfer); + } + else + { + ret = soc_dma_alloc_list_item(&dma_list, dma_list); + + if (ret != DRV_RC_OK) + { + goto fail; + } + } + + dma_list->dest.addr = (void *)(&(buf[i * (len_per_buf / sizeof(uint32_t))])); + dma_list->size = len_per_buf / sizeof(uint32_t); + } + + // Create a circular list if we are doing circular buffering + if (num_bufs != 0) + { + dma_list->next = &(i2s_info->dma_cfg[channel].xfer); + } + + // Setup and start the DMA engine + ret = soc_dma_config(&(i2s_info->dma_ch[channel]), &(i2s_info->dma_cfg[channel])); + + if (ret != DRV_RC_OK) + { + goto fail; + } + + ret = soc_dma_start_transfer(&(i2s_info->dma_ch[channel])); + + if (ret != DRV_RC_OK) + { + goto fail; + } + + // Enable the channel and let it go! + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); + reg |= (1 << (i2s_reg_map[channel].ctrl_en)); + reg |= (1 << (i2s_reg_map[channel].ctrl_sync_rst)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; + + return DRV_RC_OK; + +fail: + i2s_disable(channel); + soc_dma_release(&(i2s_info->dma_ch[channel])); + return DRV_RC_FAIL; +} + +DRIVER_API_RC soc_i2s_stop_listen(void) +{ + uint8_t channel = I2S_CHANNEL_RX; + uint32_t save; + + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (!(i2s_info->en[channel])) + { + return DRV_RC_FAIL; + } + + save = interrupt_lock(); + i2s_disable(channel); + interrupt_unlock(save); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len) +{ + // Calling stream with 0 buffers is the same as a onetime write of the whole buffer + return soc_i2s_stream(buf, len, 0); +} + +DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs) +{ + DRIVER_API_RC ret; + uint8_t channel = I2S_CHANNEL_TX; + uint32_t reg; + uint32_t len_per_buf; + int i; + struct soc_dma_xfer_item *dma_list; + + // Check channel no in use and configured + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (i2s_info->en[channel] || !(i2s_info->cfgd[channel])) + { + return DRV_RC_FAIL; + } + + // Get a DMA channel + ret = soc_dma_acquire(&(i2s_info->dma_ch[channel])); + + if (ret != DRV_RC_OK) + { + return DRV_RC_FAIL; + } + + // Enable the channel + i2s_enable(channel); + + // Determine the length of a single buffer + if (num_bufs == 0) + { + len_per_buf = len; + } + else + { + len_per_buf = len / num_bufs; + } + + // Prep some configuration + i2s_info->dma_cfg[channel].type = SOC_DMA_TYPE_MEM2PER; + i2s_info->dma_cfg[channel].dest_interface = SOC_DMA_INTERFACE_I2S_TX; + i2s_info->dma_cfg[channel].dest_step_count = 0; + i2s_info->dma_cfg[channel].src_step_count = 0; + + i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_NONE; + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[channel].xfer.dest.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); + i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_INCR; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; + + if (num_bufs == 0) + { + i2s_info->dma_cfg[channel].cb_done = i2s_dma_cb_done; + i2s_info->dma_cfg[channel].cb_done_arg = (void *)((uint32_t)channel); + } + else + { + i2s_info->dma_cfg[channel].cb_block = i2s_dma_cb_block; + i2s_info->dma_cfg[channel].cb_block_arg = (void *)((uint32_t)channel); + } + + i2s_info->dma_cfg[channel].cb_err = i2s_dma_cb_err; + i2s_info->dma_cfg[channel].cb_err_arg = (void *)((uint32_t)channel); + + // Setup the linked list + for (i = 0; i < ((num_bufs == 0) ? 1 : num_bufs); i++) + { + if (i == 0) + { + dma_list = &(i2s_info->dma_cfg[channel].xfer); + } + else + { + ret = soc_dma_alloc_list_item(&dma_list, dma_list); + + if (ret != DRV_RC_OK) + { + goto fail; + } + } + + dma_list->src.addr = (void *)(&(buf[i * (len_per_buf / sizeof(uint32_t))])); + dma_list->size = len_per_buf / sizeof(uint32_t); + } + + // Create a circular list if we are doing circular buffering + if (num_bufs != 0) + { + dma_list->next = &(i2s_info->dma_cfg[channel].xfer); + } + + // Setup and start the DMA engine + ret = soc_dma_config(&(i2s_info->dma_ch[channel]), &(i2s_info->dma_cfg[channel])); + + if (ret != DRV_RC_OK) + { + goto fail; + } + + ret = soc_dma_start_transfer(&(i2s_info->dma_ch[channel])); + + if (ret != DRV_RC_OK) + { + goto fail; + } + + // Enable the channel and let it go! + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl); + reg |= (1 << (i2s_reg_map[channel].ctrl_en)); + reg |= (1 << (i2s_reg_map[channel].ctrl_sync_rst)); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].ctrl) = reg; + + return DRV_RC_OK; + +fail: + i2s_disable(channel); + soc_dma_release(&(i2s_info->dma_ch[channel])); + return DRV_RC_FAIL; +} + + +DRIVER_API_RC soc_i2s_stop_stream(void) +{ + uint8_t channel = I2S_CHANNEL_TX; + uint32_t save; + + if (channel >= I2S_NUM_CHANNELS) + { + return DRV_RC_FAIL; + } + else if (!(i2s_info->en[channel])) + { + return DRV_RC_FAIL; + } + + save = interrupt_lock(); + i2s_disable(channel); + interrupt_unlock(save); + + return DRV_RC_OK; +} + +/* Driver API */ +DRIVER_API_RC soc_i2s_init() +{ + int i; + uint32_t reg; + + // Prep info struct + for (i = 0; i < I2S_NUM_CHANNELS; i++) + { + i2s_info->en[i] = 0; + i2s_info->cfgd[i] = 0; + i2s_info->cfg[i].cb_done = NULL; + i2s_info->cfg[i].cb_err = NULL; + } + + // Enable global clock, use local clock gating per channel instead + set_clock_gate(i2s_info->clk_gate_info, CLK_GATE_ON); + + // Setup ISR (and enable) + SET_INTERRUPT_HANDLER(i2s_info->int_vector, i2s_interrupt_handler); + SOC_UNMASK_INTERRUPTS(i2s_info->int_mask); + + // Set up control register + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL); + reg |= (1 << SOC_I2S_CTRL_TR_CFG_0); + reg &= ~(1 << SOC_I2S_CTRL_TSYNC_LOOP_BACK); + reg &= ~(1 << SOC_I2S_CTRL_RSYNC_LOOP_BACK); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL) = reg; + + // Set the watermark levels + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) &= 0xFFFCFFFF; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_TFIFO_CTRL) |= (I2S_TFIFO_THR << SOC_I2S_TFIFO_CTRL_TAFULL_THRS); + + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) &= 0xFFFCFFFF; + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_RFIFO_CTRL) |= (I2S_RFIFO_THR << SOC_I2S_RFIFO_CTRL_RAFULL_THRS); + + // Enable global interrupt mask + reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL); + reg |= (1 << SOC_I2S_CID_CTRL_INTREQ_MASK); + MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CID_CTRL) = reg; + + // Initially, have all channels disabled + for (i = 0; i < I2S_NUM_CHANNELS; i++) + { + i2s_disable(i); + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2s_reset(uint8_t channel) +{ + i2s_info->en[channel] = 0; + i2s_info->cfgd[channel] = 0; + i2s_info->cfg[channel].cb_done = NULL; + i2s_info->cfg[channel].cb_err = NULL; + + i2s_info->cfg[channel].cb_done_arg = NULL; + i2s_info->cfg[channel].cb_err_arg = NULL; + + + i2s_info->dma_ch[channel].active = 0; + i2s_info->dma_ch[channel].id = 0; + i2s_info->dma_ch[channel].ll = NULL; + i2s_info->dma_ch[channel].curr = NULL; + + i2s_info->dma_cfg[channel].cb_done_arg = NULL; + i2s_info->dma_cfg[channel].cb_done = NULL; + i2s_info->dma_cfg[channel].cb_block_arg= NULL; + i2s_info->dma_cfg[channel].cb_block = NULL; + i2s_info->dma_cfg[channel].cb_err_arg = NULL; + i2s_info->dma_cfg[channel].cb_err = NULL; + + soc_i2s_config(channel, &(i2s_info->cfg[channel])); + + return DRV_RC_OK; +} diff --git a/system/libarc32_arduino101/drivers/soc_i2s.h b/system/libarc32_arduino101/drivers/soc_i2s.h new file mode 100644 index 00000000..5a14f5f9 --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_i2s.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_I2s_H_ +#define SOC_I2s_H_ + +#include "data_type.h" +#include "soc_dma.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup common_drivers Common Drivers + * Definition of the drivers APIs accessible from any processor. + * @ingroup drivers + */ + +/** + * @defgroup soc_i2s Quark SE SOC I2S + * Quark SE SOC I2S (Audio) drivers API. + * @ingroup common_drivers + * @{ + */ + +// I2S channels +#define I2S_CHANNEL_TX 0 +#define I2S_CHANNEL_RX 1 +#define I2S_NUM_CHANNELS 2 + +// I2S modes +#define I2S_MODE_SCK_POL (0x01) +#define I2S_MODE_WS_POL (0x02) +#define I2S_MODE_LR_ALIGN (0x08) +#define I2S_MODE_SAMPLE_DEL (0x10) +#define I2S_MODE_WS_DSP (0x20) + +#define I2S_MODE_PHILLIPS (I2S_MODE_SCK_POL | I2S_MODE_LR_ALIGN) +#define I2S_MODE_RJ (I2S_MODE_SCK_POL | I2S_MODE_WS_POL | \ + I2S_MODE_SAMPLE_DEL) +#define I2S_MODE_LJ (I2S_MODE_SCK_POL | I2S_MODE_WS_POL | \ + I2S_MODE_LR_ALIGN | I2S_MODE_SAMPLE_DEL) +#define I2S_MODE_DSP (I2S_MODE_SCK_POL | I2S_MODE_LR_ALIGN | \ + I2S_MODE_WS_DSP) + +// I2S configuration object +struct soc_i2s_cfg { + uint16_t sample_rate; // in Hz + uint8_t resolution; + uint8_t mode; + uint8_t master; + + void (*cb_done)(void *); + void *cb_done_arg; + + void (*cb_err)(void *); + void *cb_err_arg; +}; + +// Internal struct for use by the controller (and soc_config) +struct soc_i2s_info { + uint32_t reg_base; + uint32_t int_vector; + uint32_t int_mask; + + uint32_t clk_speed; + + struct soc_i2s_cfg cfg[I2S_NUM_CHANNELS]; + uint8_t en[I2S_NUM_CHANNELS]; + uint8_t cfgd[I2S_NUM_CHANNELS]; + + struct soc_dma_cfg dma_cfg[I2S_NUM_CHANNELS]; + struct soc_dma_channel dma_ch[I2S_NUM_CHANNELS]; + + struct clk_gate_info_s *clk_gate_info; +}; + +extern struct driver soc_i2s_driver; + +/** + * Function to configure specified I2S channel + * + * Configuration parameters must be valid or an error is returned - see return values below. + * + * @param channel : I2S channel number + * @param cfg : pointer to configuration structure + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_INVALID_CONFIG - if any configuration parameters are not valid + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg); + +/** + * Function to deconfigure specified I2S channel + * + * @param channel : I2S channel number + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); + +/** + * Function to transmit a block of audio data + * + * @param buf : pointer to data to write + * @param len : length of data to write (in bytes) + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len); + +/** + * Function to continuously transmit blocks of audio data + * + * @param buf : pointer to buffer to read data from + * @param len : length of buffer (in bytes) + * @param num_bufs : number of parts into which to split the buffer; calling the callback + * after each is sent + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs); + +/** + * Function to stop a continuous audio data write + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_stop_stream(void); + +/** + * Function to receive a block of audio data + * + * @param buf : pointer to buffer to fill with data + * @param len : length of buffer (in bytes) + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len); + +/** + * Function to continuously receive blocks of audio data + * + * @param buf : pointer to buffer to fill with data + * @param len : length of buffer (in bytes) + * @param num_bufs : number of parts into which to split the buffer; calling the callback + * after each is filled + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs); + +/** + * Function to stop a continuous audio data read + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2s_stop_listen(void); + +DRIVER_API_RC soc_i2s_init(); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index c7e60d8ae65766a0241c1e77c6dc01dd110b940b..705a4986ce2e5ebf496ccc6a8b5386fb18d5b0ea 100644 GIT binary patch delta 95193 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 G^Zp+++HOz) delta 51482 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 From 5f3ee5bb36dc5e69ce26f7d2a64220ebc927ad83 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 12 Jul 2016 10:22:12 +0200 Subject: [PATCH 067/222] define digitalPinToInterrupt for backwards compatibility see http://forum.arduino.cc/index.php?topic=370167.0 --- cores/arduino/Arduino.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 625951a9..cc6cb593 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -43,6 +43,8 @@ extern "C"{ #define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SYSTEM_CORE_CLOCK / 1000L) ) #define microsecondsToClockCycles(a) ( (a) * (SYSTEM_CORE_CLOCK / 1000000L) ) +#define digitalPinToInterrupt(P) ( P ) + void yield(void); /* sketch */ From 2ec9b94f941d34ee1419311b194707aad3b0ee67 Mon Sep 17 00:00:00 2001 From: Dino Tinitigan Date: Mon, 11 Jul 2016 14:47:59 -0700 Subject: [PATCH 068/222] Update Wire examples to use Serial instead of Serial1 -change Serial to Serial1 in the master_writer and master_reader examples --- libraries/Wire/examples/master_reader/master_reader.ino | 6 +++--- libraries/Wire/examples/master_writer/master_writer.ino | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index dca6ce88..b6748b18 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -15,7 +15,7 @@ void setup() { Wire.begin(); // join i2c bus (address optional for master) - Serial1.begin(9600); // start serial for output + Serial.begin(9600); // start serial for output } void loop() @@ -25,8 +25,8 @@ void loop() while (Wire.available()) // slave may send less than requested { char c = Wire.read(); // receive a byte as character - Serial1.print(c); // print the character - Serial1.println(); + Serial.print(c); // print the character + Serial.println(); } diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index 61065d5d..5304fd81 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -15,7 +15,7 @@ void setup() { Wire.begin(); // join i2c bus (address optional for master) - Serial1.begin(9600); + Serial.begin(9600); } byte x = 1; @@ -26,9 +26,9 @@ void loop() //Wire.write("x is "); // sends five bytes Wire.write(x); // sends one byte int result = Wire.endTransmission(); // stop transmitting - Serial1.println(); - Serial1.print("x = "); - Serial1.print(x); + Serial.println(); + Serial.print("x = "); + Serial.print(x); x++; delay(500); } From bdaec192070ab196a55282fa57512748c6f1edd9 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Mon, 11 Jul 2016 11:21:34 -0700 Subject: [PATCH 069/222] Add CurieIMUClass::end() Add end() method to IMU class, to disable clocking to the SPI controller. This is unlikely to have noticeable power-saving effects, however it is a good habit to get into. --- libraries/CurieIMU/src/CurieIMU.cpp | 5 +++++ libraries/CurieIMU/src/CurieIMU.h | 1 + libraries/CurieIMU/src/internal/ss_spi.c | 6 ++++++ libraries/CurieIMU/src/internal/ss_spi.h | 1 + 4 files changed, 13 insertions(+) diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index d397121a..0a91cc73 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -57,6 +57,11 @@ bool CurieIMUClass::begin() return (CURIE_IMU_CHIP_ID == getDeviceID()); } +void CurieIMUClass::end() +{ + ss_spi_disable(); +} + int CurieIMUClass::getGyroRate() { int rate; diff --git a/libraries/CurieIMU/src/CurieIMU.h b/libraries/CurieIMU/src/CurieIMU.h index 7f6c6968..c27aa314 100644 --- a/libraries/CurieIMU/src/CurieIMU.h +++ b/libraries/CurieIMU/src/CurieIMU.h @@ -95,6 +95,7 @@ class CurieIMUClass : public BMI160Class { public: bool begin(void); + void end(void); // supported values: 25, 50, 100, 200, 400, 800, 1600, 3200 (Hz) int getGyroRate(); diff --git a/libraries/CurieIMU/src/internal/ss_spi.c b/libraries/CurieIMU/src/internal/ss_spi.c index 9aafbb8e..5905aad5 100644 --- a/libraries/CurieIMU/src/internal/ss_spi.c +++ b/libraries/CurieIMU/src/internal/ss_spi.c @@ -73,6 +73,12 @@ void ss_spi_init() SS_SPI_REG_WRITE(INTR_MASK, SPI_DISABLE_INT); } +void ss_spi_disable() +{ + /* gate SPI controller clock */ + SS_SPI_REG_WRITE(CTRL, 0); +} + static inline void spi_transmit(uint8_t *buf, size_t count, boolean_t waitCompletion) { while (count--) diff --git a/libraries/CurieIMU/src/internal/ss_spi.h b/libraries/CurieIMU/src/internal/ss_spi.h index 1d60b33a..f41d8f92 100644 --- a/libraries/CurieIMU/src/internal/ss_spi.h +++ b/libraries/CurieIMU/src/internal/ss_spi.h @@ -25,6 +25,7 @@ extern "C" { #endif void ss_spi_init(); +void ss_spi_disable(); int ss_spi_xfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt); #ifdef __cplusplus From c59e2808e1bf27e8adc7c3aff0d0ed1a8344e04f Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Fri, 15 Jul 2016 15:39:16 -0700 Subject: [PATCH 070/222] Issue #241: make Serial1 release GPIO pins on end() UARTClass::init() muxes out the UART pins to Arduino header pins 0/1. Reset the mux on UARTClass::end() so that pins 0/1 can be used as GPIOs again. --- cores/arduino/UARTClass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 8a74192d..87250d17 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -112,6 +112,9 @@ void UARTClass::end( void ) opened = false; // Clear any received data _rx_buffer->_iHead = _rx_buffer->_iTail; + + SET_PIN_MODE(17, GPIO_MUX_MODE); // Rdx SOC PIN (Arduino header pin 0) + SET_PIN_MODE(16, GPIO_MUX_MODE); // Txd SOC PIN (Arduino header pin 1) } void UARTClass::setInterruptPriority(uint32_t priority) From b8162e993cccbe4065c1bd55d1f4466669f01f75 Mon Sep 17 00:00:00 2001 From: Caihong Ma Date: Mon, 4 Jul 2016 15:15:54 +0800 Subject: [PATCH 071/222] Jira566: I2S DMA implement: supplement library and example --- .../I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino | 31 +++-- .../I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino | 2 +- libraries/CurieI2S/src/CurieI2SDMA.cpp | 93 +++++++++++---- libraries/CurieI2S/src/CurieI2SDMA.h | 10 +- system/libarc32_arduino101/drivers/soc_i2s.c | 106 +++++++++--------- system/libarc32_arduino101/drivers/soc_i2s.h | 8 +- 6 files changed, 155 insertions(+), 95 deletions(-) diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino index 97ab8163..6992bf56 100644 --- a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino @@ -25,7 +25,7 @@ uint32_t dataBuff[BUFF_SIZE+OFFSET]; // extra 2 buffer is for the padding zero uint8_t start_flag = 0; uint8_t done_flag = 0; uint32_t loop_count = 0; - +uint32_t shift_count = 0; void setup() { Serial.begin(115200); @@ -46,32 +46,45 @@ void setup() void loop() { - int status = CurieI2SDMA.transRX(dataBuff,sizeof(dataBuff)); + int status = CurieI2SDMA.transRX(dataBuff,sizeof(dataBuff),sizeof(uint32_t)); if(status) return; + // find out first non-zero + shift_count = 0; + for(uint32_t i = 0;i <= OFFSET;++i) + { + if(dataBuff[i] == 0) + shift_count++; + else + break; + } + if(shift_count > OFFSET) + return; + if(start_flag) { - if((dataBuff[OFFSET]>>16) != loop_count+1) + if((dataBuff[shift_count]>>16) != loop_count+1) Serial.println("+++ loop_count jump +++"); } else { start_flag = 1; } - loop_count = (dataBuff[OFFSET] >> 16); - + loop_count = (dataBuff[shift_count] >> 16); + + // check data done_flag = 1; for(uint32_t i = 0 ;i < BUFF_SIZE;++i) { - //Serial.println(dataBuff[i+OFFSET],HEX); - if ((dataBuff[i+OFFSET] & 0XFFFF0000) == (loop_count <<16) - && (dataBuff[i+OFFSET] & 0XFFFF) == (i+1)) + //Serial.println(dataBuff[i+shift_count],HEX); + if ((dataBuff[i+shift_count] & 0XFFFF0000) == (loop_count <<16) + && (dataBuff[i+shift_count] & 0XFFFF) == (i+1)) ; else { done_flag = 0; - Serial.println(dataBuff[i+OFFSET],HEX); + Serial.println(dataBuff[i+shift_count],HEX); Serial.println("ERROR"); break; } diff --git a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino index fe27ab2e..d39bea36 100644 --- a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino @@ -38,7 +38,7 @@ void loop() dataBuff[i] = i + 1 + (loop_count<<16); } loop_count++; - int status = CurieI2SDMA.transTX(dataBuff,sizeof(dataBuff)); + int status = CurieI2SDMA.transTX(dataBuff,sizeof(dataBuff),sizeof(uint32_t)); if(status) return; diff --git a/libraries/CurieI2S/src/CurieI2SDMA.cpp b/libraries/CurieI2S/src/CurieI2SDMA.cpp index 4ef36428..9ac8de50 100644 --- a/libraries/CurieI2S/src/CurieI2SDMA.cpp +++ b/libraries/CurieI2S/src/CurieI2SDMA.cpp @@ -36,10 +36,11 @@ volatile uint8_t txerror_flag = 0; volatile uint8_t rxdone_flag = 0; volatile uint8_t rxerror_flag = 0; - +uint8_t frameDelay = 0; static void txi2s_done(void* x) { + CurieI2SDMA.lastFrameDelay(); txdone_flag = 1; return; @@ -76,6 +77,11 @@ Curie_I2SDMA::Curie_I2SDMA() { } +void Curie_I2SDMA::lastFrameDelay() +{ + delay(frameDelay); +} + int Curie_I2SDMA::iniTX() { muxTX(1); @@ -154,8 +160,8 @@ int Curie_I2SDMA::beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master txcfg.cb_err = txi2s_err; txdone_flag = 0; txerror_flag = 0; + frameDelay = 5; soc_i2s_config(I2S_CHANNEL_TX, &txcfg); - return I2S_DMA_OK; } @@ -195,10 +201,11 @@ int Curie_I2SDMA::beginRX(uint16_t sample_rate,uint8_t resolution,uint8_t master return I2S_DMA_OK; } -int Curie_I2SDMA::transTX(uint32_t* buf_TX,uint32_t len) +int Curie_I2SDMA::transTX(void* buf_TX,uint32_t len,uint32_t len_per_data) { - soc_i2s_stream(buf_TX, len,0); - + int status = soc_i2s_stream(buf_TX, len,len_per_data,0); + if(status) + return I2S_DMA_FAIL; while (1) { // check the DMA and I2S status @@ -215,9 +222,11 @@ int Curie_I2SDMA::transTX(uint32_t* buf_TX,uint32_t len) } } -int Curie_I2SDMA::transRX(uint32_t* buf_RX,uint32_t len) +int Curie_I2SDMA::transRX(void* buf_RX,uint32_t len,uint32_t len_per_data) { - soc_i2s_listen(buf_RX, len ,0); + int status = soc_i2s_listen(buf_RX, len ,len_per_data,0); + if(status) + return I2S_DMA_FAIL; while (1) { @@ -248,28 +257,66 @@ void Curie_I2SDMA::stopRX() muxRX(0); } -int Curie_I2SDMA::mergeData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_TX) +int Curie_I2SDMA::mergeData(void* buf_left,void* buf_right,void* buf_TX,uint32_t length_TX,uint32_t len_per_data) { - int length = (int)(sizeof(buf_left) / sizeof(buf_left[0])); - for(int i = 0; i < length;++i) + if(len_per_data == 1) { - buf_TX[2*i] = buf_left[i]; - buf_TX[2*i+1] = buf_right[i]; + for(uint32_t i = 0; i < length_TX/2;++i) + { + *((uint8_t *)buf_TX+2*i) = *((uint8_t *)buf_left+i); + *((uint8_t *)buf_TX+2*i+1) = *((uint8_t *)buf_right+i); + } } + else if(len_per_data == 2) + { + for(uint32_t i = 0; i < length_TX/2;++i) + { + *((uint16_t *)buf_TX+2*i) = *((uint16_t *)buf_left+i); + *((uint16_t *)buf_TX+2*i+1) = *((uint16_t *)buf_right+i); + } + } + else if(len_per_data == 4) + { + for(uint32_t i = 0; i < length_TX/2;++i) + { + *((uint32_t *)buf_TX+2*i) = *((uint32_t *)buf_left+i); + *((uint32_t *)buf_TX+2*i+1) = *((uint32_t *)buf_right+i); + } + } + else + return I2S_DMA_FAIL; - return I2S_DMA_OK; + return I2S_DMA_OK; } -int Curie_I2SDMA::separateData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_RX) -{ - int length1 = (int)( sizeof(buf_RX) / sizeof(buf_RX[0])/2 ); - int length2 = (int)( sizeof(buf_left) / sizeof(buf_left[0]) ); - int length = length1 < length2 ? length1 : length2; - - for(int i = 0; i < length;++i) +int Curie_I2SDMA::separateData(void* buf_left,void* buf_right,void* buf_RX,uint32_t length_RX,uint32_t len_per_data) +{ + if(len_per_data == 1) + { + for(uint32_t i = 0; i < length_RX/2;++i) + { + *((uint8_t *)buf_left+i) = *((uint8_t *)buf_RX+2*i); + *((uint8_t *)buf_right+i) = *((uint8_t *)buf_RX+2*i+1); + } + } + else if(len_per_data == 2) { - buf_left[i] = buf_RX[2*i]; - buf_right[i] = buf_RX[2*i+1]; + for(uint32_t i = 0; i < length_RX/2;++i) + { + *((uint16_t *)buf_left+i) = *((uint16_t *)buf_RX+2*i); + *((uint16_t *)buf_right+i) = *((uint16_t *)buf_RX+2*i+1); + } } - return I2S_DMA_OK; + else if(len_per_data == 4) + { + for(uint32_t i = 0; i < length_RX/2;++i) + { + *((uint32_t *)buf_left+i) = *((uint32_t *)buf_RX+2*i); + *((uint32_t *)buf_right+i) = *((uint32_t *)buf_RX+2*i+1); + } + } + else + return I2S_DMA_FAIL; + + return I2S_DMA_OK; } diff --git a/libraries/CurieI2S/src/CurieI2SDMA.h b/libraries/CurieI2S/src/CurieI2SDMA.h index a1707123..3f026ef8 100644 --- a/libraries/CurieI2S/src/CurieI2SDMA.h +++ b/libraries/CurieI2S/src/CurieI2SDMA.h @@ -47,6 +47,8 @@ class Curie_I2SDMA public: Curie_I2SDMA(); + void lastFrameDelay(); + // int beginTX(uint16_t sample_rate,uint8_t resolution,uint8_t master,uint8_t mode); // @@ -58,16 +60,16 @@ class Curie_I2SDMA int iniRX(); // starts transmission of data to the tx channel - int transTX(uint32_t* buf_TX,uint32_t len); + int transTX(void* buf_TX,uint32_t len,uint32_t len_per_data); // starts listening to the rx channel - int transRX(uint32_t* buf_RX,uint32_t len); + int transRX(void* buf_RX,uint32_t len,uint32_t len_per_data); // merge data of left and right channel into one buffer - int mergeData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_TX); + int mergeData(void* buf_left,void* buf_right,void* buf_TX,uint32_t length_TX,uint32_t len_per_data); // seperate the data to left and right channl - int separateData(uint32_t* buf_left,uint32_t* buf_right,uint32_t* buf_RX); + int separateData(void* buf_left,void* buf_right,void* buf_RX,uint32_t length_RX,uint32_t len_per_data); // void stopTX(); diff --git a/system/libarc32_arduino101/drivers/soc_i2s.c b/system/libarc32_arduino101/drivers/soc_i2s.c index 70b51429..114ce764 100644 --- a/system/libarc32_arduino101/drivers/soc_i2s.c +++ b/system/libarc32_arduino101/drivers/soc_i2s.c @@ -57,11 +57,11 @@ static void i2s_disable(uint8_t channel); static void i2s_isr(void); DRIVER_API_RC soc_i2s_config(uint8_t channel, struct soc_i2s_cfg *cfg); DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); -DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len); -DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs); +DRIVER_API_RC soc_i2s_read(void *buf, uint32_t len, uint32_t len_per_data); +DRIVER_API_RC soc_i2s_listen(void *buf, uint32_t len, uint32_t len_per_data, uint8_t num_bufs); DRIVER_API_RC soc_i2s_stop_listen(void); -DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len); -DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs); +DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data); +DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs); DRIVER_API_RC soc_i2s_stop_stream(void); DRIVER_API_RC soc_i2s_init(); @@ -196,19 +196,12 @@ static void i2s_dma_cb_done(void *num) if(channel == I2S_CHANNEL_TX) { - if((0x00200000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL)) - && !(0x18000000 & MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_CTRL))) - { - for(int i = 0; i < 4; ++i) - MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, SOC_I2S_DATA_REG) = 0x0; - } - do { reg = MMIO_REG_VAL_FROM_BASE(SOC_I2S_BASE, i2s_reg_map[channel].fifo_stat); - } while(reg & 0x000000FF); + } while(reg & 0x000000FF); } - + if (i2s_info->cfg[channel].cb_done) { i2s_info->cfg[channel].cb_done(i2s_info->cfg[channel].cb_done_arg); @@ -294,13 +287,13 @@ DRIVER_API_RC soc_i2s_deconfig(uint8_t channel) return DRV_RC_OK; } -DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len) +DRIVER_API_RC soc_i2s_read(void *buf, uint32_t len, uint32_t len_per_data) { // Calling listen with 0 buffers is the same as a onetime read of the whole buffer - return soc_i2s_listen(buf, len, 0); + return soc_i2s_listen(buf, len, len_per_data, 0); } -DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs) +DRIVER_API_RC soc_i2s_listen(void *buf, uint32_t len, uint32_t len_per_data, uint8_t num_bufs) { DRIVER_API_RC ret; uint8_t channel = I2S_CHANNEL_RX; @@ -347,10 +340,26 @@ DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs) i2s_info->dma_cfg[channel].src_step_count = 0; i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_INCR; - i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_NONE; - i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; i2s_info->dma_cfg[channel].xfer.src.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); + + if(len_per_data == 1) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_8; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_8; + } + else if(len_per_data == 2) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_16; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_16; + } + else if(len_per_data == 4) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; + } + else + return DRV_RC_FAIL; if (num_bufs == 0) { @@ -383,8 +392,8 @@ DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs) } } - dma_list->dest.addr = (void *)(&(buf[i * (len_per_buf / sizeof(uint32_t))])); - dma_list->size = len_per_buf / sizeof(uint32_t); + dma_list->dest.addr = (void *)(uint8_t *)(buf+i * len_per_buf ); + dma_list->size = len_per_buf / len_per_data; } // Create a circular list if we are doing circular buffering @@ -443,13 +452,13 @@ DRIVER_API_RC soc_i2s_stop_listen(void) return DRV_RC_OK; } -DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len) +DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data) { // Calling stream with 0 buffers is the same as a onetime write of the whole buffer - return soc_i2s_stream(buf, len, 0); + return soc_i2s_stream(buf, len, len_per_data, 0); } -DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs) +DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs) { DRIVER_API_RC ret; uint8_t channel = I2S_CHANNEL_TX; @@ -496,11 +505,27 @@ DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs) i2s_info->dma_cfg[channel].src_step_count = 0; i2s_info->dma_cfg[channel].xfer.dest.delta = SOC_DMA_DELTA_NONE; - i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; i2s_info->dma_cfg[channel].xfer.dest.addr = (void *)(SOC_I2S_BASE + SOC_I2S_DATA_REG); i2s_info->dma_cfg[channel].xfer.src.delta = SOC_DMA_DELTA_INCR; - i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; + if(len_per_data == 1) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_8; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_8; + } + else if(len_per_data == 2) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_16; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_16; + } + else if(len_per_data == 4) + { + i2s_info->dma_cfg[channel].xfer.dest.width = SOC_DMA_WIDTH_32; + i2s_info->dma_cfg[channel].xfer.src.width = SOC_DMA_WIDTH_32; + } + else + return DRV_RC_FAIL;; + if (num_bufs == 0) { i2s_info->dma_cfg[channel].cb_done = i2s_dma_cb_done; @@ -532,8 +557,8 @@ DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs) } } - dma_list->src.addr = (void *)(&(buf[i * (len_per_buf / sizeof(uint32_t))])); - dma_list->size = len_per_buf / sizeof(uint32_t); + dma_list->src.addr = (void *)(uint8_t *)(buf+i * len_per_buf ); + dma_list->size = len_per_buf / len_per_data; } // Create a circular list if we are doing circular buffering @@ -643,30 +668,3 @@ DRIVER_API_RC soc_i2s_init() return DRV_RC_OK; } -DRIVER_API_RC soc_i2s_reset(uint8_t channel) -{ - i2s_info->en[channel] = 0; - i2s_info->cfgd[channel] = 0; - i2s_info->cfg[channel].cb_done = NULL; - i2s_info->cfg[channel].cb_err = NULL; - - i2s_info->cfg[channel].cb_done_arg = NULL; - i2s_info->cfg[channel].cb_err_arg = NULL; - - - i2s_info->dma_ch[channel].active = 0; - i2s_info->dma_ch[channel].id = 0; - i2s_info->dma_ch[channel].ll = NULL; - i2s_info->dma_ch[channel].curr = NULL; - - i2s_info->dma_cfg[channel].cb_done_arg = NULL; - i2s_info->dma_cfg[channel].cb_done = NULL; - i2s_info->dma_cfg[channel].cb_block_arg= NULL; - i2s_info->dma_cfg[channel].cb_block = NULL; - i2s_info->dma_cfg[channel].cb_err_arg = NULL; - i2s_info->dma_cfg[channel].cb_err = NULL; - - soc_i2s_config(channel, &(i2s_info->cfg[channel])); - - return DRV_RC_OK; -} diff --git a/system/libarc32_arduino101/drivers/soc_i2s.h b/system/libarc32_arduino101/drivers/soc_i2s.h index 5a14f5f9..61692103 100644 --- a/system/libarc32_arduino101/drivers/soc_i2s.h +++ b/system/libarc32_arduino101/drivers/soc_i2s.h @@ -143,7 +143,7 @@ DRIVER_API_RC soc_i2s_deconfig(uint8_t channel); * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len); +DRIVER_API_RC soc_i2s_write(void *buf, uint32_t len, uint32_t len_per_data); /** * Function to continuously transmit blocks of audio data @@ -157,7 +157,7 @@ DRIVER_API_RC soc_i2s_write(uint32_t *buf, uint32_t len); * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_stream(uint32_t *buf, uint32_t len, uint32_t num_bufs); +DRIVER_API_RC soc_i2s_stream(void *buf, uint32_t len, uint32_t len_per_data, uint32_t num_bufs); /** * Function to stop a continuous audio data write @@ -178,7 +178,7 @@ DRIVER_API_RC soc_i2s_stop_stream(void); * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len); +DRIVER_API_RC soc_i2s_read(void *buf, uint32_t len, uint32_t len_per_data); /** * Function to continuously receive blocks of audio data @@ -192,7 +192,7 @@ DRIVER_API_RC soc_i2s_read(uint32_t *buf, uint32_t len); * - DRV_RC_OK on success * - DRV_RC_FAIL otherwise */ -DRIVER_API_RC soc_i2s_listen(uint32_t *buf, uint32_t len, uint8_t num_bufs); +DRIVER_API_RC soc_i2s_listen(void *buf, uint32_t len, uint32_t len_per_data, uint8_t num_bufs); /** * Function to stop a continuous audio data read From 12b2376ea58c79ef00ea47af2aea8796bb652d69 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Wed, 20 Jul 2016 15:23:23 -0700 Subject: [PATCH 072/222] ATLEDGE-643: Add chip ID to SerialFlash example sketch RawHardwareTest reports the 101's on-board SPI flash chip as an unknown device. Fix this by adding the device's JEDEC ID to the example sketch. --- .../SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino b/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino index 7cd47cb2..74afa10a 100644 --- a/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino +++ b/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino @@ -391,6 +391,7 @@ const char * id2chip(const unsigned char *id) // Winbond if (id[1] == 0x40) { if (id[2] == 0x14) return "W25Q80BV"; + if (id[2] == 0x15) return "W25Q16DV"; if (id[2] == 0x17) return "W25Q64FV"; if (id[2] == 0x18) return "W25Q128FV"; if (id[2] == 0x19) return "W25Q256FV"; From 5671917298c35e6164784da6929cf006daf9d51d Mon Sep 17 00:00:00 2001 From: caihongm Date: Fri, 27 May 2016 02:17:19 +0800 Subject: [PATCH 073/222] Jira509:add IMU examples:FreeFallDetection, MotionDetection,ZeroMotionDetection; change CurieIMU.cpp line490 from 'setZeroMotionDetectionThreshold' to 'setZeroMtionDetectionDuration' --- .../ZeroMotionDetect/ZeroMotionDetect.ino | 41 ++++++++++++------- libraries/CurieIMU/src/CurieIMU.cpp | 12 +----- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino index 9ac2cc65..56c9b79e 100644 --- a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino +++ b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino @@ -9,40 +9,53 @@ */ #include "CurieIMU.h" -boolean blinkState = false; // state of the LED -unsigned long loopTime = 0; // get the time since program started -unsigned long interruptsTime = 0; // get the time when zero motion event is detected +boolean ledState = false; // state of the LED void setup() { Serial.begin(9600); while(!Serial); // wait for the serial port to open /* Initialise the IMU */ - blinkState = CurieIMU.begin(); + CurieIMU.begin(); CurieIMU.attachInterrupt(eventCallback); /* Enable Zero Motion Detection */ - CurieIMU.setDetectionThreshold(CURIE_IMU_ZERO_MOTION, 1500); // 1.5g=1500mg - CurieIMU.setDetectionDuration(CURIE_IMU_ZERO_MOTION, 25); // 25s + CurieIMU.setDetectionThreshold(CURIE_IMU_ZERO_MOTION, 50); // 50mg + CurieIMU.setDetectionDuration(CURIE_IMU_ZERO_MOTION, 2); // 2s CurieIMU.interrupts(CURIE_IMU_ZERO_MOTION); + /* Enable Motion Detection */ + CurieIMU.setDetectionThreshold(CURIE_IMU_MOTION, 20); // 20mg + CurieIMU.setDetectionDuration(CURIE_IMU_MOTION, 10); // trigger times of consecutive slope data points + CurieIMU.interrupts(CURIE_IMU_MOTION); + Serial.println("IMU initialisation complete, waiting for events..."); } void loop() { - //if zero motion is detected in 1500ms, LED will be turned up - loopTime = millis(); - if(abs(loopTime -interruptsTime) < 1500) - blinkState = true; - else - blinkState = false; - digitalWrite(13, blinkState); + // if zero motion is detected, LED will be turned up. + digitalWrite(13, ledState); } static void eventCallback(void){ if (CurieIMU.getInterruptStatus(CURIE_IMU_ZERO_MOTION)) { - interruptsTime = millis(); + ledState = true; Serial.println("zero motion detected..."); } + if (CurieIMU.getInterruptStatus(CURIE_IMU_MOTION)) { + ledState = false; + if (CurieIMU.motionDetected(X_AXIS, POSITIVE)) + Serial.println("Negative motion detected on X-axis"); + if (CurieIMU.motionDetected(X_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on X-axis"); + if (CurieIMU.motionDetected(Y_AXIS, POSITIVE)) + Serial.println("Negative motion detected on Y-axis"); + if (CurieIMU.motionDetected(Y_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on Y-axis"); + if (CurieIMU.motionDetected(Z_AXIS, POSITIVE)) + Serial.println("Negative motion detected on Z-axis"); + if (CurieIMU.motionDetected(Z_AXIS, NEGATIVE)) + Serial.println("Positive motion detected on Z-axis"); + } } /* diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index 0a91cc73..d8dd7966 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -432,8 +432,6 @@ float CurieIMUClass::getDetectionThreshold(int feature) return getTapDetectionThreshold(); case CURIE_IMU_STEP: - case CURIE_IMU_TAP_SHOCK: - case CURIE_IMU_TAP_QUIET: case CURIE_IMU_DOUBLE_TAP: case CURIE_IMU_FIFO_FULL: case CURIE_IMU_DATA_READY: @@ -466,8 +464,6 @@ void CurieIMUClass::setDetectionThreshold(int feature, float threshold) break; case CURIE_IMU_STEP: - case CURIE_IMU_TAP_SHOCK: - case CURIE_IMU_TAP_QUIET: case CURIE_IMU_DOUBLE_TAP: case CURIE_IMU_FIFO_FULL: case CURIE_IMU_DATA_READY: @@ -795,7 +791,7 @@ void CurieIMUClass::setDetectionDuration(int feature, float value) break; case CURIE_IMU_ZERO_MOTION: - setZeroMotionDetectionThreshold(value); + setZeroMotionDetectionDuration(value); break; case CURIE_IMU_TAP_QUIET: @@ -1465,8 +1461,6 @@ void CurieIMUClass::enableInterrupt(int feature, bool enabled) setIntDataReadyEnabled(enabled); break; - case CURIE_IMU_TAP_QUIET: - case CURIE_IMU_TAP_SHOCK: default: break; } @@ -1502,8 +1496,6 @@ bool CurieIMUClass::interruptsEnabled(int feature) case CURIE_IMU_DATA_READY: return getIntDataReadyEnabled(); - case CURIE_IMU_TAP_QUIET: - case CURIE_IMU_TAP_SHOCK: default: return false; } @@ -1539,8 +1531,6 @@ bool CurieIMUClass::getInterruptStatus(int feature) case CURIE_IMU_DATA_READY: return getIntDataReadyStatus(); - case CURIE_IMU_TAP_QUIET: - case CURIE_IMU_TAP_SHOCK: default: return false; } From 197434001a973ad7a8df18b823f8365988140b43 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Sun, 17 Jul 2016 00:33:17 -0700 Subject: [PATCH 074/222] Issue #149: Provide scaled IMU data Add implementations of readAccelerometer and readGyro which return values that are scaled according to the range set with setAccelerometerRange and setGyroRange --- .../examples/Accelerometer/Accelerometer.ino | 22 +---- libraries/CurieIMU/examples/Gyro/Gyro.ino | 22 +---- libraries/CurieIMU/keywords.txt | 3 + libraries/CurieIMU/src/BMI160.h | 3 + libraries/CurieIMU/src/CurieIMU.cpp | 92 +++++++++++++++++++ libraries/CurieIMU/src/CurieIMU.h | 11 ++- 6 files changed, 114 insertions(+), 39 deletions(-) diff --git a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino index 22069c61..a2553b4d 100644 --- a/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino +++ b/libraries/CurieIMU/examples/Accelerometer/Accelerometer.ino @@ -23,16 +23,10 @@ void setup() { } void loop() { - int axRaw, ayRaw, azRaw; // raw accelerometer values - float ax, ay, az; + float ax, ay, az; //scaled accelerometer values - // read raw accelerometer measurements from device - CurieIMU.readAccelerometer(axRaw, ayRaw, azRaw); - - // convert the raw accelerometer data to G's - ax = convertRawAcceleration(axRaw); - ay = convertRawAcceleration(ayRaw); - az = convertRawAcceleration(azRaw); + // read accelerometer measurements from device, scaled to the configured range + CurieIMU.readAccelerometerScaled(ax, ay, az); // display tab-separated accelerometer x/y/z values Serial.print("a:\t"); @@ -44,16 +38,6 @@ void loop() { Serial.println(); } -float convertRawAcceleration(int aRaw) { - // since we are using 2G range - // -2g maps to a raw value of -32768 - // +2g maps to a raw value of 32767 - - float a = (aRaw * 2.0) / 32768.0; - - return a; -} - /* Copyright (c) 2016 Intel Corporation. All rights reserved. diff --git a/libraries/CurieIMU/examples/Gyro/Gyro.ino b/libraries/CurieIMU/examples/Gyro/Gyro.ino index a7752659..56d0b64e 100644 --- a/libraries/CurieIMU/examples/Gyro/Gyro.ino +++ b/libraries/CurieIMU/examples/Gyro/Gyro.ino @@ -23,16 +23,10 @@ void setup() { } void loop() { - int gxRaw, gyRaw, gzRaw; // raw gyro values - float gx, gy, gz; + float gx, gy, gz; //scaled Gyro values - // read raw gyro measurements from device - CurieIMU.readGyro(gxRaw, gyRaw, gzRaw); - - // convert the raw gyro data to degrees/second - gx = convertRawGyro(gxRaw); - gy = convertRawGyro(gyRaw); - gz = convertRawGyro(gzRaw); + // read gyro measurements from device, scaled to the configured range + CurieIMU.readGyroScaled(gx, gy, gz); // display tab-separated gyro x/y/z values Serial.print("g:\t"); @@ -44,16 +38,6 @@ void loop() { Serial.println(); } -float convertRawGyro(int gRaw) { - // since we are using 250 degrees/seconds range - // -250 maps to a raw value of -32768 - // +250 maps to a raw value of 32767 - - float g = (gRaw * 250.0) / 32768.0; - - return g; -} - /* Copyright (c) 2016 Intel Corporation. All rights reserved. diff --git a/libraries/CurieIMU/keywords.txt b/libraries/CurieIMU/keywords.txt index 874baf4f..1c64688b 100644 --- a/libraries/CurieIMU/keywords.txt +++ b/libraries/CurieIMU/keywords.txt @@ -59,11 +59,14 @@ setStepCountEnabled KEYWORD1 resetStepCount KEYWORD1 readMotionSensor KEYWORD1 +readMotionSensorScaled KEYWORD1 readAcceleration KEYWORD1 readRotation KEYWORD1 readAccelerometer KEYWORD1 +readAccelerometerScaled KEYWORD1 readGyro KEYWORD1 +readGyroScaled KEYWORD1 readTemperature KEYWORD1 shockDetected KEYWORD1 diff --git a/libraries/CurieIMU/src/BMI160.h b/libraries/CurieIMU/src/BMI160.h index 2c9f3654..b452965a 100644 --- a/libraries/CurieIMU/src/BMI160.h +++ b/libraries/CurieIMU/src/BMI160.h @@ -35,6 +35,9 @@ THE SOFTWARE. #include "Arduino.h" +#define BMI160_SENSOR_RANGE 65535.0f +#define BMI160_SENSOR_LOW 32768.0f + #define BMI160_SPI_READ_BIT 7 #define BMI160_RA_CHIP_ID 0x00 diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index d8dd7966..635f9026 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -232,14 +232,19 @@ void CurieIMUClass::setGyroRange(int range) if (range >= 2000) { bmiRange = BMI160_GYRO_RANGE_2000; + gyro_range = 2000.0f; } else if (range >= 1000) { bmiRange = BMI160_GYRO_RANGE_1000; + gyro_range = 1000.0f; } else if (range >= 500) { bmiRange = BMI160_GYRO_RANGE_500; + gyro_range = 500.0f; } else if (range >= 250) { bmiRange = BMI160_GYRO_RANGE_250; + gyro_range = 250.0f; } else { bmiRange = BMI160_GYRO_RANGE_125; + gyro_range = 125.0f; } setFullScaleGyroRange(bmiRange); @@ -277,12 +282,16 @@ void CurieIMUClass::setAccelerometerRange(int range) if (range <= 2) { bmiRange = BMI160_ACCEL_RANGE_2G; + accel_range = 2.0f; } else if (range <= 4) { bmiRange = BMI160_ACCEL_RANGE_4G; + accel_range = 4.0f; } else if (range <= 8) { bmiRange = BMI160_ACCEL_RANGE_8G; + accel_range = 8.0f; } else { bmiRange = BMI160_ACCEL_RANGE_16G; + accel_range = 16.0f; } setFullScaleAccelRange(bmiRange); @@ -1546,6 +1555,18 @@ void CurieIMUClass::setStepDetectionMode(int mode) BMI160Class::setStepDetectionMode((BMI160StepMode)mode); } +float CurieIMUClass::convertRaw(int16_t raw, float range_abs) +{ + float slope; + float val; + + /* Input range will be -32768 to 32767 + * Output range must be -range_abs to range_abs */ + val = (float) raw; + slope = (range_abs * 2.0f) / BMI160_SENSOR_RANGE; + return -(range_abs) + slope * (val + BMI160_SENSOR_LOW); +} + void CurieIMUClass::readMotionSensor(int& ax, int& ay, int& az, int& gx, int& gy, int& gz) { short sax, say, saz, sgx, sgy, sgz; @@ -1560,6 +1581,21 @@ void CurieIMUClass::readMotionSensor(int& ax, int& ay, int& az, int& gx, int& gy gz = sgz; } +void CurieIMUClass::readMotionSensorScaled(float& ax, float& ay, float& az, + float& gx, float& gy, float& gz) +{ + int16_t sax, say, saz, sgx, sgy, sgz; + + getMotion6(&sax, &say, &saz, &sgx, &sgy, &sgz); + + ax = convertRaw(sax, accel_range); + ay = convertRaw(say, accel_range); + az = convertRaw(saz, accel_range); + gx = convertRaw(sgx, gyro_range); + gy = convertRaw(sgy, gyro_range); + gz = convertRaw(sgz, gyro_range); +} + void CurieIMUClass::readAccelerometer(int& x, int& y, int& z) { short sx, sy, sz; @@ -1571,6 +1607,17 @@ void CurieIMUClass::readAccelerometer(int& x, int& y, int& z) z = sz; } +void CurieIMUClass::readAccelerometerScaled(float& x, float& y, float& z) +{ + int16_t sx, sy, sz; + + getAcceleration(&sx, &sy, &sz); + + x = convertRaw(sx, accel_range); + y = convertRaw(sy, accel_range); + z = convertRaw(sz, accel_range); +} + void CurieIMUClass::readGyro(int& x, int& y, int& z) { short sx, sy, sz; @@ -1582,6 +1629,17 @@ void CurieIMUClass::readGyro(int& x, int& y, int& z) z = sz; } +void CurieIMUClass::readGyroScaled(float& x, float& y, float& z) +{ + int16_t sx, sy, sz; + + getRotation(&sx, &sy, &sz); + + x = convertRaw(sx, gyro_range); + y = convertRaw(sy, gyro_range); + z = convertRaw(sz, gyro_range); +} + int CurieIMUClass::readAccelerometer(int axis) { if (axis == X_AXIS) { @@ -1595,6 +1653,23 @@ int CurieIMUClass::readAccelerometer(int axis) return 0; } +float CurieIMUClass::readAccelerometerScaled(int axis) +{ + int16_t raw; + + if (axis == X_AXIS) { + raw = getAccelerationX(); + } else if (axis == Y_AXIS) { + raw = getAccelerationY(); + } else if (axis == Z_AXIS) { + raw = getAccelerationZ(); + } else { + return 0; + } + + return convertRaw(raw, accel_range); +} + int CurieIMUClass::readGyro(int axis) { if (axis == X_AXIS) { @@ -1608,6 +1683,23 @@ int CurieIMUClass::readGyro(int axis) return 0; } +float CurieIMUClass::readGyroScaled(int axis) +{ + int16_t raw; + + if (axis == X_AXIS) { + raw = getRotationX(); + } else if (axis == Y_AXIS) { + raw = getRotationY(); + } else if (axis == Z_AXIS) { + raw = getRotationZ(); + } else { + return 0; + } + + return convertRaw(raw, gyro_range); +} + int CurieIMUClass::readTemperature() { return getTemperature(); diff --git a/libraries/CurieIMU/src/CurieIMU.h b/libraries/CurieIMU/src/CurieIMU.h index c27aa314..8056b135 100644 --- a/libraries/CurieIMU/src/CurieIMU.h +++ b/libraries/CurieIMU/src/CurieIMU.h @@ -187,11 +187,15 @@ class CurieIMUClass : public BMI160Class { void setStepDetectionMode(int mode); void readMotionSensor(int& ax, int& ay, int& az, int& gx, int& gy, int& gz); + void readMotionSensorScaled(float& ax, float& ay, float& az, float& gx, float& gy, float& gz); void readAccelerometer(int& x, int& y, int& z); + void readAccelerometerScaled(float& x, float& y, float& z); void readGyro(int& x, int& y, int& z); - + void readGyroScaled(float& x, float& y, float& z); int readAccelerometer(int axis); + float readAccelerometerScaled(int axis); int readGyro(int axis); + float readGyroScaled(int axis); int readTemperature(); bool shockDetected(int axis, int direction); @@ -205,6 +209,9 @@ class CurieIMUClass : public BMI160Class { private: int serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt); + float accel_range; + float gyro_range; + float getFreefallDetectionThreshold(); void setFreefallDetectionThreshold(float threshold); float getShockDetectionThreshold(); @@ -231,6 +238,8 @@ class CurieIMUClass : public BMI160Class { int getDoubleTapDetectionDuration(); void setDoubleTapDetectionDuration(int duration); + float convertRaw(int16_t raw, float range_abs); + void enableInterrupt(int feature, bool enabled); void (*_user_callback)(void); From 160751a8c47f1d4cdd647ad1bf0d8eb6312d5791 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Fri, 22 Jul 2016 18:21:27 -0700 Subject: [PATCH 075/222] README.md: add "commit message how-to" wiki link --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9bde6e77..a710c0f3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,12 @@ Future upgrades may fail since the internal contents were modified by hand. In order to recover, shut down the IDE, delete the entire `Arduino15` directory, then restart the IDE. +# Pull Requests + +Before submitting a pull request, please see our +[guidelines](https://github.com/01org/corelibs-arduino101/wiki/Writing-a-commit-message) +for writing a considerate commit message. + # Support & Issues If you have found a bug, or you believe a new feature should be added, please From fbb7b02a89da37ac9408710ff5ed1a936d00cd8b Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Tue, 19 Jul 2016 09:13:39 +0800 Subject: [PATCH 076/222] JIRA-640 I2C operations are sometimes timing out causing a long delay in between i2C operations fix this issue by call complete callback if no stop command issue at the end of transfer. --- cores/arduino/i2c.c | 37 +++++++++---------- libraries/Wire/examples/bus_scan/bus_scan.ino | 1 + system/libarc32_arduino101/drivers/i2c_priv.h | 1 + .../libarc32_arduino101/drivers/ss_dw_i2c.c | 12 ++++-- .../libarc32_arduino101/drivers/ss_dw_i2c.h | 2 +- .../drivers/ss_i2c_iface.c | 11 +++++- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cores/arduino/i2c.c b/cores/arduino/i2c.c index 164a7562..6b1b0aff 100644 --- a/cores/arduino/i2c.c +++ b/cores/arduino/i2c.c @@ -48,7 +48,8 @@ static void ss_i2c_err(uint32_t dev_id) i2c_err_source = dev_id; } -static int wait_rx_or_err(bool no_stop){ +static int wait_rx_or_err() +{ uint64_t timeout = TIMEOUT_MS * 200; while(timeout--) { if (i2c_err_detect) { @@ -65,20 +66,17 @@ static int wait_rx_or_err(bool no_stop){ return I2C_ERROR_OTHER; // other error } } - if (!no_stop) { - if (i2c_rx_complete) { - return I2C_OK; - } + if (i2c_rx_complete) { + return I2C_OK; } delayMicroseconds(10); } - if (!no_stop) - return I2C_TIMEOUT; - else - return I2C_OK; + + return I2C_TIMEOUT; } -static int wait_tx_or_err(bool no_stop){ +static int wait_tx_or_err() +{ uint64_t timeout = TIMEOUT_MS * 200; while(timeout--) { if (i2c_err_detect) { @@ -95,17 +93,12 @@ static int wait_tx_or_err(bool no_stop){ return I2C_ERROR_OTHER; // other error } } - if (!no_stop) { - if (i2c_tx_complete) { + if (i2c_tx_complete) { return I2C_OK; - } } delayMicroseconds(10); } - if (!no_stop) - return I2C_TIMEOUT; - else - return I2C_OK; + return I2C_TIMEOUT; } static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ @@ -116,9 +109,13 @@ static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ if (ret == I2C_OK) { return I2C_OK; } - if (ret == I2C_BUSY) { + else if (ret == I2C_BUSY) { delayMicroseconds(10); } + else + { + return I2C_TIMEOUT - ret; + } } return I2C_TIMEOUT - ret; } @@ -202,7 +199,7 @@ int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop) i2c_err_detect = 0; i2c_err_source = 0; ss_i2c_transfer(I2C_SENSING_0, bytes, length, 0, 0, i2c_slave, no_stop); - ret = wait_tx_or_err(no_stop); + ret = wait_tx_or_err(); if (ret) return ret; ret = wait_dev_ready(I2C_SENSING_0, no_stop); @@ -219,7 +216,7 @@ int i2c_readbytes(uint8_t *buf, int length, bool no_stop) i2c_err_detect = 0; i2c_err_source = 0; ss_i2c_transfer(I2C_SENSING_0, 0, 0, buf, length, i2c_slave, no_stop); - ret = wait_rx_or_err(no_stop); + ret = wait_rx_or_err(); if (ret) return ret; ret = wait_dev_ready(I2C_SENSING_0, no_stop); diff --git a/libraries/Wire/examples/bus_scan/bus_scan.ino b/libraries/Wire/examples/bus_scan/bus_scan.ino index 11e39373..e816ea79 100644 --- a/libraries/Wire/examples/bus_scan/bus_scan.ino +++ b/libraries/Wire/examples/bus_scan/bus_scan.ino @@ -42,6 +42,7 @@ void setup() Wire.begin(); Serial.begin(115200); + while(!Serial); } boolean toggle = false; // state of the LED diff --git a/system/libarc32_arduino101/drivers/i2c_priv.h b/system/libarc32_arduino101/drivers/i2c_priv.h index d6bb585f..ba6dc142 100644 --- a/system/libarc32_arduino101/drivers/i2c_priv.h +++ b/system/libarc32_arduino101/drivers/i2c_priv.h @@ -133,6 +133,7 @@ typedef struct i2c_info { uint8_t *i2c_write_buff; uint8_t *i2c_read_buff; uint8_t restart; + uint8_t send_stop; /* Callbacks */ IO_CB_FUNC tx_cb; diff --git a/system/libarc32_arduino101/drivers/ss_dw_i2c.c b/system/libarc32_arduino101/drivers/ss_dw_i2c.c index 7f4b3b03..6f43bc78 100644 --- a/system/libarc32_arduino101/drivers/ss_dw_i2c.c +++ b/system/libarc32_arduino101/drivers/ss_dw_i2c.c @@ -92,7 +92,7 @@ static void recv_data(i2c_info_pt dev) } -void i2c_fill_fifo(i2c_info_pt dev, bool no_stop) +void i2c_fill_fifo(i2c_info_pt dev) { uint32_t i, tx_cnt, data; @@ -114,7 +114,7 @@ void i2c_fill_fifo(i2c_info_pt dev, bool no_stop) if( dev->tx_len == 1) { // last byte to write - if (! no_stop) + if (dev->send_stop) data |= I2C_STOP_CMD; } dev->tx_len -= 1; @@ -125,7 +125,7 @@ void i2c_fill_fifo(i2c_info_pt dev, bool no_stop) data = I2C_PUSH_DATA | I2C_READ_CMD; if (dev->rx_tx_len == 1) { // last dummy byte to write - if(! no_stop) + if(dev->send_stop) data |= I2C_STOP_CMD; if(dev->restart) { @@ -143,13 +143,17 @@ void i2c_fill_fifo(i2c_info_pt dev, bool no_stop) static void xmit_data(i2c_info_pt dev) { int mask; - i2c_fill_fifo(dev, false); + i2c_fill_fifo(dev); if (dev->rx_tx_len <= 0) { mask = REG_READ( I2C_INTR_MASK ); mask &= ~(R_TX_EMPTY); mask |= R_STOP_DETECTED; REG_WRITE(I2C_INTR_MASK, mask); + if ((dev->rx_len == 0) && (!dev->send_stop)) + { + end_data_transfer( dev ); + } } } diff --git a/system/libarc32_arduino101/drivers/ss_dw_i2c.h b/system/libarc32_arduino101/drivers/ss_dw_i2c.h index b5dd100c..f40f822b 100644 --- a/system/libarc32_arduino101/drivers/ss_dw_i2c.h +++ b/system/libarc32_arduino101/drivers/ss_dw_i2c.h @@ -39,7 +39,7 @@ #define SS_DW_I2C_H_ #include void i2c_mst_err_ISR_proc(i2c_info_pt dev); -void i2c_fill_fifo(i2c_info_pt dev, bool no_stop); +void i2c_fill_fifo(i2c_info_pt dev); void i2c_mst_rx_avail_ISR_proc(i2c_info_pt dev); void i2c_mst_tx_req_ISR_proc(i2c_info_pt dev); void i2c_mst_stop_detected_ISR_proc(i2c_info_pt dev); diff --git a/system/libarc32_arduino101/drivers/ss_i2c_iface.c b/system/libarc32_arduino101/drivers/ss_i2c_iface.c index 200ed273..199bdc8f 100644 --- a/system/libarc32_arduino101/drivers/ss_i2c_iface.c +++ b/system/libarc32_arduino101/drivers/ss_i2c_iface.c @@ -347,6 +347,15 @@ DRIVER_API_RC ss_i2c_transfer(I2C_CONTROLLER controller_id, uint8_t *data_write, return DRV_RC_FAIL; } + if (!no_stop) + { + dev->send_stop = true; + } + else + { + dev->send_stop = false; + } + if ((data_read_len == 0) && (data_write_len == 0)) { //Workaround: we know that we are doing I2C bus scan. @@ -376,7 +385,7 @@ DRIVER_API_RC ss_i2c_transfer(I2C_CONTROLLER controller_id, uint8_t *data_write, dev->i2c_read_buff = data_read; dev->total_read_bytes = 0; dev->total_write_bytes = 0; - i2c_fill_fifo(dev, no_stop); + i2c_fill_fifo(dev); interrupt_unlock(saved); From e3d90c19d96bbab006f59151b73179ab0c7d9097 Mon Sep 17 00:00:00 2001 From: Caihong Ma Date: Tue, 26 Jul 2016 01:34:39 +0800 Subject: [PATCH 077/222] CurieI2SDMA: Fix typo and add explanatory notes CurieI2SDMA.h: Fix typo at line 23 and 24; I2SDMA_RXCallBack.ino: add explanatory notes to explain how to check the verification of data --- .../I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino | 18 ++++++++++++------ libraries/CurieI2S/src/CurieI2SDMA.h | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino index 6992bf56..92d40298 100644 --- a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino @@ -20,12 +20,17 @@ #define BUFF_SIZE 128 #define OFFSET 2 -uint32_t dataBuff[BUFF_SIZE+OFFSET]; // extra 2 buffer is for the padding zero +uint32_t dataBuff[BUFF_SIZE+OFFSET]; // extra 2 buffers are for the padding zero +/** + * the received data: the higher 16 bits should be equal to loop_count and the lower 16 bits should be (0x01~0x80) + * loop_count should increase by 1 in evry loop() + * for example: if first time the received data is 0x00010001~0x00010080, then next time the data should be 0x00020001~0x00020080 +**/ uint8_t start_flag = 0; -uint8_t done_flag = 0; -uint32_t loop_count = 0; -uint32_t shift_count = 0; +uint8_t done_flag = 0; // when done_flag is 1, the received data are correct +uint32_t loop_count = 0; // record the higher 16 bits of received data +uint32_t shift_count = 0; // the position of first non-zero void setup() { Serial.begin(115200); @@ -61,7 +66,8 @@ void loop() } if(shift_count > OFFSET) return; - + + // record the higher 16 bits of received data if(start_flag) { if((dataBuff[shift_count]>>16) != loop_count+1) @@ -73,7 +79,7 @@ void loop() } loop_count = (dataBuff[shift_count] >> 16); - // check data + // check data serial: the higher 16 bits should be equal to loop_count and the lower 16 bits should be (0x01~0x80) done_flag = 1; for(uint32_t i = 0 ;i < BUFF_SIZE;++i) { diff --git a/libraries/CurieI2S/src/CurieI2SDMA.h b/libraries/CurieI2S/src/CurieI2SDMA.h index 3f026ef8..271d6ac4 100644 --- a/libraries/CurieI2S/src/CurieI2SDMA.h +++ b/libraries/CurieI2S/src/CurieI2SDMA.h @@ -20,8 +20,8 @@ //CurieI2SDMA.h -#ifndef _CURI2SDMA_H_ -#define _CURI2SDMA_H_ +#ifndef _CURIEI2SDMA_H_ +#define _CURIEI2SDMA_H_ #include From 9a871b671ceec5f625c63c9a9e58f044cef2e70c Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Wed, 27 Jul 2016 14:20:29 -0700 Subject: [PATCH 078/222] Add delay to Serial1.end() allow GPIO lines to settle Through testing, it was discovered that if Serial1.begin() is called again immediately after Serial1.end(), then any attempt to write data immediately following the begin() call could result in corrupted frames. After calling Serial1.end(), it will be at least 300us before those pins can be used as UART again. --- cores/arduino/UARTClass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 87250d17..3ada5ccc 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -25,6 +25,8 @@ #include "wiring_constants.h" #include "wiring_digital.h" +#define SETTLING_TIME 400 + extern void UART_Handler(void); extern void serialEventRun(void) __attribute__((weak)); extern void serialEvent(void) __attribute__((weak)); @@ -115,6 +117,7 @@ void UARTClass::end( void ) SET_PIN_MODE(17, GPIO_MUX_MODE); // Rdx SOC PIN (Arduino header pin 0) SET_PIN_MODE(16, GPIO_MUX_MODE); // Txd SOC PIN (Arduino header pin 1) + delayMicroseconds(SETTLING_TIME); // wait for lines to settle } void UARTClass::setInterruptPriority(uint32_t priority) From b317284ec9312288dea4e2b5db5696821fa6237f Mon Sep 17 00:00:00 2001 From: Calvin Sangbin Park Date: Thu, 28 Jul 2016 10:44:44 -0700 Subject: [PATCH 079/222] Update libarc to the latest --- variants/arduino_101/libarc32drv_arduino101.a | Bin 488918 -> 488868 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index 705a4986ce2e5ebf496ccc6a8b5386fb18d5b0ea..608d192ca812cd8ccdbcd10a4a490a6d6fbbd94d 100644 GIT binary patch delta 25085 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 Z%Jd90%B)qfEIYFH6`oXq_Wv03e*kCqtXlv8 From 9ae91d3e9d55d81358681dd1595880de1176d640 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Aug 2016 09:49:30 -0600 Subject: [PATCH 080/222] Jira-556: Add comments to I2S examples --- .../I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino | 14 +++++++++----- .../examples/I2S_RxCallback/I2S_RxCallback.ino | 13 +++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino index 92d40298..a41f25f3 100644 --- a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino @@ -10,11 +10,15 @@ * To test this sketch you will need a second Arduino/Genuino 101 board with the I2SDMA_TxCallback sketch uploaded * * Connection: - * GND -> GND - * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) - * I2S_RWS(pin 3) -> I2S_TWS(pin 4) - * I2S_RXD(pin 5) -> I2S_TXD(pin 7) - * + * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) + * I2S_RWS (pin 3) -> I2S_TWS (pin 4) + * I2S_RXD (pin 5) -> I2S_TXD (pin 7) + * Ground (GND) -> Ground (GND) + * Notes: + * Transmission is sensitive to noise. To reduce noise: + * - Power both boards with an external power supply. Usb power is not always clean. + * - Insure that both boards are sharing the same ground. + * - Use short wires to connect between the board or use shielded wire. **/ #include diff --git a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino index 1222f7f5..101d3774 100644 --- a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino +++ b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino @@ -5,10 +5,15 @@ * To test this sketch you will need a second Arduino/Genuino 101 board with the I2S_TxCallback sketch uploaded * * Connection: - * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) - * I2S_RWS(pin 3) -> I2S_TWS(pin 4) - * I2S_RXD(pin 5) -> I2S_TXD(pin 7) - * + * I2S_RSCK(pin 8) -> I2S_TSCK(pin 2) + * I2S_RWS (pin 3) -> I2S_TWS (pin 4) + * I2S_RXD (pin 5) -> I2S_TXD (pin 7) + * Ground (GND) -> Ground (GND) + * Notes: + * Transmission is sensitive to noise. To reduce noise: + * - Power both boards with an external power supply. Usb power is not always clean. + * - Insure that both boards are sharing the same ground. + * - Use short wires to connect between the board or use shielded wire. **/ #include From 48b0e58306d227b289316fcb4143edb08570042c Mon Sep 17 00:00:00 2001 From: Calvin Sangbin Park Date: Wed, 3 Aug 2016 14:16:23 -0700 Subject: [PATCH 081/222] Update libarc to the latest --- variants/arduino_101/libarc32drv_arduino101.a | Bin 488868 -> 488868 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index 608d192ca812cd8ccdbcd10a4a490a6d6fbbd94d..9161cd367244a5ff9a034e3bdea6515640dffecf 100644 GIT binary patch delta 581 zcmZ4TT6W26*$GnY<_1Ql7M5lk6&H#_*`|{j-NiRQ5dSBHBJfA+pEOKhGo$-kZWsrw zoF`aH07*b%vum;?FI?c@af!`y3uMEg0%p?#4>L(@zIj|W8bxHgs4`<@CaO?x4`X8( zs*vtuM$=rlP@^KV03pL~5JfNP9IxyaJAWvd@pdWLg z2V4lKTzvb3Y0O4*;6iIN*(J9d8MCmIb3nt)aJ$_qmOlz`?qt1WvF#D3S=?mdLeu*a z*(A2_d%?2B7$NpgiBWv}L>X4r0Jzxpc{!|0`rur!NeRDM*#zK1+w-{DzSzRKU=|25$Wk+YzjjW(Rs{hmWv|N z5WrNX4HYq&-l)hdv0b!=$9;Wms7QkVM3{Z^>cp z>q8Mq_|3`&3r(n(TDjTo+M+0G@ML3?fQdkCTbjr=6WKQL?J-l?l3>wj0=EC|ayHLE sm^QFyU4F93!J-OkTO%9$TXmQsh}pe*?2^`SA;;4!;@gj8vOnMk0D0Q2H2?qr From 7366ed0a4fd26faec64e11b530557c313069b4f7 Mon Sep 17 00:00:00 2001 From: Adrien Descamps Date: Wed, 3 Aug 2016 01:40:57 +0200 Subject: [PATCH 082/222] Flush wait for transmission to be complete In previous version, flush wait for the transmission to be complete by checking if the transmission holding register (or fifo) is empty. When this happen, the last byte is still in the shift register, and has still to be transmitted. This mean we can't know when the transmission is actually complete, which is crucial to implement RS485 communication, for example. This commit change this behaviour and wait for the shift register to be empty, which means the transmission is really complete. --- cores/arduino/UARTClass.cpp | 2 +- system/libarc32_arduino101/drivers/ns16550.c | 13 +++++++++++++ system/libarc32_arduino101/drivers/uart.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 3ada5ccc..72a10c0e 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -169,7 +169,7 @@ void UARTClass::flush( void ) { while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent // Wait for transmission to complete - while (uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX)); + while(!uart_tx_complete(CONFIG_UART_CONSOLE_INDEX)); } size_t UARTClass::write( const uint8_t uc_data ) diff --git a/system/libarc32_arduino101/drivers/ns16550.c b/system/libarc32_arduino101/drivers/ns16550.c index 2a9d081f..5fe5548f 100644 --- a/system/libarc32_arduino101/drivers/ns16550.c +++ b/system/libarc32_arduino101/drivers/ns16550.c @@ -626,3 +626,16 @@ void uart_int_connect(int which, /* UART to which to connect */ /* set the Host Processor Interrupt Routing Mask */ SOC_UNMASK_INTERRUPTS(INT_UART_0_MASK + (which * UART_REG_ADDR_INTERVAL)); } + +/******************************************************************************* +* +* uart_tx_complete - check if tx holding and shift register are empty +* +* RETURNS: zero if registers are non-empty (transmission not complete), +* non-zero if registers are empty (transmission complete) +*/ + +uint8_t uart_tx_complete(int which) +{ + return INBYTE(LSR(which)) & LSR_TEMT; +} diff --git a/system/libarc32_arduino101/drivers/uart.h b/system/libarc32_arduino101/drivers/uart.h index 5ca430cd..76cae337 100644 --- a/system/libarc32_arduino101/drivers/uart.h +++ b/system/libarc32_arduino101/drivers/uart.h @@ -91,6 +91,7 @@ int uart_line_status(int port); int uart_break_check(int port); void uart_break_send(int port, int delay); void uart_disable(int port); +uint8_t uart_tx_complete(int which); #ifdef __cplusplus } From e4a5b14c51e70933ff3f85603a08c3b6970ec264 Mon Sep 17 00:00:00 2001 From: Adrien Descamps Date: Sat, 6 Aug 2016 16:27:35 +0200 Subject: [PATCH 083/222] Fix UART receiver corruption When the UART receiver is disconnected for a time shorter than a line break and longer than a start bit, it interpret that as a received packet, and if data are transmitted immediatly after, they are corrupted. This commit is a workarround for that bug, that enable the loopback feature of the UART when UART is disconnected, so the UART module does not notice it is disconnected. A previous workarround for this bug (a forced delay after disconnection) is not needed anymore and is removed. --- cores/arduino/UARTClass.cpp | 7 ++-- system/libarc32_arduino101/drivers/ns16550.c | 36 ++++++++++++++++++++ system/libarc32_arduino101/drivers/uart.h | 2 ++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 72a10c0e..922cf74d 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -25,8 +25,6 @@ #include "wiring_constants.h" #include "wiring_digital.h" -#define SETTLING_TIME 400 - extern void UART_Handler(void); extern void serialEventRun(void) __attribute__((weak)); extern void serialEvent(void) __attribute__((weak)); @@ -114,10 +112,13 @@ void UARTClass::end( void ) opened = false; // Clear any received data _rx_buffer->_iHead = _rx_buffer->_iTail; + + //enable loopback, needed to prevent a short disconnection to be + //interpreted as a packet and corrupt receiver state + uart_loop_enable(CONFIG_UART_CONSOLE_INDEX); SET_PIN_MODE(17, GPIO_MUX_MODE); // Rdx SOC PIN (Arduino header pin 0) SET_PIN_MODE(16, GPIO_MUX_MODE); // Txd SOC PIN (Arduino header pin 1) - delayMicroseconds(SETTLING_TIME); // wait for lines to settle } void UARTClass::setInterruptPriority(uint32_t priority) diff --git a/system/libarc32_arduino101/drivers/ns16550.c b/system/libarc32_arduino101/drivers/ns16550.c index 5fe5548f..386c6b22 100644 --- a/system/libarc32_arduino101/drivers/ns16550.c +++ b/system/libarc32_arduino101/drivers/ns16550.c @@ -639,3 +639,39 @@ uint8_t uart_tx_complete(int which) { return INBYTE(LSR(which)) & LSR_TEMT; } + +/******************************************************************************* +* +* uart_loop_enable - enable loopback +* +* This function enable the local loopback. +* When enabled, the output of the Transmitter Shift +* Register is looped back into the Receiver Shift Register input, +* and any data that is transmitted is immediately received. +* +* RETURNS: N/A +*/ + +void uart_loop_enable(int which) +{ + uint8_t mdc = INBYTE(MDC(which)); + mdc |= MCR_LOOP; + OUTBYTE(MDC(which), mdc); +} + +/******************************************************************************* +* +* uart_loop_disable - disable loopback +* +* This function disable the local loopback. +* +* RETURNS: N/A +*/ + +void uart_loop_disable(int which) +{ + uint8_t mdc = INBYTE(MDC(which)); + mdc &= ~MCR_LOOP; + OUTBYTE(MDC(which), mdc); +} + diff --git a/system/libarc32_arduino101/drivers/uart.h b/system/libarc32_arduino101/drivers/uart.h index 76cae337..ed737780 100644 --- a/system/libarc32_arduino101/drivers/uart.h +++ b/system/libarc32_arduino101/drivers/uart.h @@ -92,6 +92,8 @@ int uart_break_check(int port); void uart_break_send(int port, int delay); void uart_disable(int port); uint8_t uart_tx_complete(int which); +void uart_loop_enable(int which); +void uart_loop_disable(int which); #ifdef __cplusplus } From 71cf8e44b3d9c28918084c0e5a6c2d1e239b1c98 Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Wed, 10 Aug 2016 13:53:03 -0600 Subject: [PATCH 084/222] JIRA-668: Removing Intel version of Adafruit_NeoPixel Signed-off-by: Brian Baltz --- .../Adafruit_NeoPixel/Adafruit_NeoPixel.cpp | 1294 ----------------- .../Adafruit_NeoPixel/Adafruit_NeoPixel.h | 179 --- libraries/Adafruit_NeoPixel/COPYING | 794 ---------- libraries/Adafruit_NeoPixel/README.md | 11 - libraries/Adafruit_NeoPixel/esp8266.c | 67 - .../examples/buttoncycler/buttoncycler.ino | 165 --- .../examples/simple/simple.ino | 47 - .../examples/strandtest/strandtest.ino | 132 -- libraries/Adafruit_NeoPixel/keywords.txt | 29 - .../Adafruit_NeoPixel/library.properties | 9 - 10 files changed, 2727 deletions(-) delete mode 100644 libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp delete mode 100644 libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h delete mode 100644 libraries/Adafruit_NeoPixel/COPYING delete mode 100644 libraries/Adafruit_NeoPixel/README.md delete mode 100644 libraries/Adafruit_NeoPixel/esp8266.c delete mode 100644 libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino delete mode 100644 libraries/Adafruit_NeoPixel/examples/simple/simple.ino delete mode 100644 libraries/Adafruit_NeoPixel/examples/strandtest/strandtest.ino delete mode 100644 libraries/Adafruit_NeoPixel/keywords.txt delete mode 100644 libraries/Adafruit_NeoPixel/library.properties diff --git a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp deleted file mode 100644 index 185bcb93..00000000 --- a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp +++ /dev/null @@ -1,1294 +0,0 @@ -/*------------------------------------------------------------------------- - Arduino library to control a wide variety of WS2811- and WS2812-based RGB - LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. - Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega - MCUs, with LEDs wired for various color orders. 8 MHz MCUs provide - output on PORTB and PORTD, while 16 MHz chips can handle most output pins - (possible exception with upper PORT registers on the Arduino Mega). - - Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, - contributions by PJRC, Michael Miller and other members of the open - source community. - - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing products - from Adafruit! - - ------------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel 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 3 of - the License, or (at your option) any later version. - - NeoPixel 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 NeoPixel. If not, see - . - -------------------------------------------------------------------------*/ - -#include "Adafruit_NeoPixel.h" - -// Constructor when length, pin and type are known at compile-time: -Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, neoPixelType t) : - brightness(0), pixels(NULL), endTime(0), begun(false) -{ - updateType(t); - updateLength(n); - setPin(p); -} - -// via Michael Vogt/neophob: empty constructor is used when strand length -// isn't known at compile-time; situations where program config might be -// read from internal flash memory or an SD card, or arrive via serial -// command. If using this constructor, MUST follow up with updateType(), -// updateLength(), etc. to establish the strand type, length and pin number! -Adafruit_NeoPixel::Adafruit_NeoPixel() : - pin(-1), brightness(0), pixels(NULL), endTime(0), begun(false), - numLEDs(0), numBytes(0), rOffset(1), gOffset(0), bOffset(2), wOffset(1) -#ifdef NEO_KHZ400 - , is800KHz(true) -#endif -{ -} - -Adafruit_NeoPixel::~Adafruit_NeoPixel() { - if(pixels) free(pixels); - if(pin >= 0) pinMode(pin, INPUT); -} - -void Adafruit_NeoPixel::begin(void) { - if(pin >= 0) { - pinMode(pin, OUTPUT); - digitalWrite(pin, LOW); - } - begun = true; -} - -void Adafruit_NeoPixel::updateLength(uint16_t n) { - if(pixels) free(pixels); // Free existing data (if any) - - // Allocate new data -- note: ALL PIXELS ARE CLEARED - numBytes = n * ((wOffset == rOffset) ? 3 : 4); - if((pixels = (uint8_t *)malloc(numBytes))) { - memset(pixels, 0, numBytes); - numLEDs = n; - } else { - numLEDs = numBytes = 0; - } -} - -void Adafruit_NeoPixel::updateType(neoPixelType t) { - boolean oldThreeBytesPerPixel = (wOffset == rOffset); // false if RGBW - - wOffset = (t >> 6) & 0b11; // See notes in header file - rOffset = (t >> 4) & 0b11; // regarding R/G/B/W offsets - gOffset = (t >> 2) & 0b11; - bOffset = t & 0b11; -#ifdef NEO_KHZ400 - is800KHz = (t < 256); // 400 KHz flag is 1<<8 -#endif - - // If bytes-per-pixel has changed (and pixel data was previously - // allocated), re-allocate to new size. Will clear any data. - if(pixels) { - boolean newThreeBytesPerPixel = (wOffset == rOffset); - if(newThreeBytesPerPixel != oldThreeBytesPerPixel) updateLength(numLEDs); - } -} - -#ifdef ESP8266 -// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution -extern "C" void ICACHE_RAM_ATTR espShow( - uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); -#endif // ESP8266 - -void Adafruit_NeoPixel::show(void) { - - if(!pixels) return; - - // Data latch = 50+ microsecond pause in the output stream. Rather than - // put a delay at the end of the function, the ending time is noted and - // the function will simply hold off (if needed) on issuing the - // subsequent round of data until the latch time has elapsed. This - // allows the mainline code to start generating the next frame of data - // rather than stalling for the latch. - while(!canShow()); - // endTime is a private member (rather than global var) so that mutliple - // instances on different pins can be quickly issued in succession (each - // instance doesn't delay the next). - - // In order to make this code runtime-configurable to work with any pin, - // SBI/CBI instructions are eschewed in favor of full PORT writes via the - // OUT or ST instructions. It relies on two facts: that peripheral - // functions (such as PWM) take precedence on output pins, so our PORT- - // wide writes won't interfere, and that interrupts are globally disabled - // while data is being issued to the LEDs, so no other code will be - // accessing the PORT. The code takes an initial 'snapshot' of the PORT - // state, computes 'pin high' and 'pin low' values, and writes these back - // to the PORT register as needed. - - noInterrupts(); // Need 100% focus on instruction timing - - -#ifdef __AVR__ -// AVR MCUs -- ATmega & ATtiny (no XMEGA) --------------------------------- - - volatile uint16_t - i = numBytes; // Loop counter - volatile uint8_t - *ptr = pixels, // Pointer to next byte - b = *ptr++, // Current byte value - hi, // PORT w/output bit set high - lo; // PORT w/output bit set low - - // Hand-tuned assembly code issues data to the LED drivers at a specific - // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) - // for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The - // datastream timing for the LED drivers allows a little wiggle room each - // way (listed in the datasheets), so the conditions for compiling each - // case are set up for a range of frequencies rather than just the exact - // 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on - // devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based - // on the datasheet figures and have not been extensively tested outside - // the canonical 8/12/16 MHz speeds; there's no guarantee these will work - // close to the extremes (or possibly they could be pushed further). - // Keep in mind only one CPU speed case actually gets compiled; the - // resulting program isn't as massive as it might look from source here. - -// 8 MHz(ish) AVR --------------------------------------------------------- -#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - - volatile uint8_t n1, n2 = 0; // First, next bits out - - // Squeezing an 800 KHz stream out of an 8 MHz chip requires code - // specific to each PORT register. At present this is only written - // to work with pins on PORTD or PORTB, the most likely use case -- - // this covers all the pins on the Adafruit Flora and the bulk of - // digital pins on the Arduino Pro 8 MHz (keep in mind, this code - // doesn't even get compiled for 16 MHz boards like the Uno, Mega, - // Leonardo, etc., so don't bother extending this out of hand). - // Additional PORTs could be added if you really need them, just - // duplicate the else and loop and change the PORT. Each add'l - // PORT will require about 150(ish) bytes of program space. - - // 10 instruction clocks per bit: HHxxxxxLLL - // OUT instructions: ^ ^ ^ (T=0,2,7) - -#ifdef PORTD // PORTD isn't present on ATtiny85, etc. - - if(port == &PORTD) { - - hi = PORTD | pinMask; - lo = PORTD & ~pinMask; - n1 = lo; - if(b & 0x80) n1 = hi; - - // Dirty trick: RJMPs proceeding to the next instruction are used - // to delay two clock cycles in one instruction word (rather than - // using two NOPs). This was necessary in order to squeeze the - // loop down to exactly 64 words -- the maximum possible for a - // relative branch. - - asm volatile( - "headD:" "\n\t" // Clk Pseudocode - // Bit 7: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 6: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 5: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 4: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 3: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 2: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 1: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "brne headD" "\n" // 2 while(i) (Z flag set above) - : [byte] "+r" (b), - [n1] "+r" (n1), - [n2] "+r" (n2), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - } else if(port == &PORTB) { - -#endif // PORTD - - // Same as above, just switched to PORTB and stripped of comments. - hi = PORTB | pinMask; - lo = PORTB & ~pinMask; - n1 = lo; - if(b & 0x80) n1 = hi; - - asm volatile( - "headB:" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 6" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 5" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 4" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 3" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 2" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 1" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 0" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "brne headB" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef PORTD - } // endif PORTB -#endif - -#ifdef NEO_KHZ400 - } else { // end 800 KHz, do 400 KHz - - // Timing is more relaxed; unrolling the inner loop for each bit is - // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out - // of need but just to trim the code size down a little. - // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical - // to the 800-on-16 code later -- the hi/lo timing between WS2811 and - // WS2812 is not simply a 2:1 scale! - - // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,4,10) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "dec %[bit]" "\n\t" // 1 bit-- (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); - } -#endif // NEO_KHZ400 - -// 12 MHz(ish) AVR -------------------------------------------------------- -#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - - // In the 12 MHz case, an optimized 800 KHz datastream (no dead time - // between bytes) requires a PORT-specific loop similar to the 8 MHz - // code (but a little more relaxed in this case). - - // 15 instruction clocks per bit: HHHHxxxxxxLLLLL - // OUT instructions: ^ ^ ^ (T=0,4,10) - - volatile uint8_t next; - -#ifdef PORTD - - if(port == &PORTD) { - - hi = PORTD | pinMask; - lo = PORTD & ~pinMask; - next = lo; - if(b & 0x80) next = hi; - - // Don't "optimize" the OUT calls into the bitTime subroutine; - // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! - asm volatile( - "headD:" "\n\t" // (T = 0) - "out %[port], %[hi]" "\n\t" // (T = 1) - "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 6 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 5 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 4 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 3 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 2 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 1 - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) - "rjmp .+0" "\n\t" // 2 nop nop (T = 3) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) - "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) - "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) - "rjmp doneD" "\n\t" - "bitTimeD:" "\n\t" // nop nop nop (T = 4) - "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) - "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "ret" "\n\t" // 4 nop nop nop nop (T = 15) - "doneD:" "\n" - : [byte] "+r" (b), - [next] "+r" (next), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - } else if(port == &PORTB) { - -#endif // PORTD - - hi = PORTB | pinMask; - lo = PORTB & ~pinMask; - next = lo; - if(b & 0x80) next = hi; - - // Same as above, just set for PORTB & stripped of comments - asm volatile( - "headB:" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port] , %[hi]" "\n\t" - "rjmp .+0" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "out %[port] , %[next]" "\n\t" - "mov %[next] , %[lo]" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[next] , %[hi]" "\n\t" - "nop" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "brne headB" "\n\t" - "rjmp doneB" "\n\t" - "bitTimeB:" "\n\t" - "out %[port], %[next]" "\n\t" - "mov %[next], %[lo]" "\n\t" - "rol %[byte]" "\n\t" - "sbrc %[byte], 7" "\n\t" - "mov %[next], %[hi]" "\n\t" - "nop" "\n\t" - "out %[port], %[lo]" "\n\t" - "ret" "\n\t" - "doneB:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef PORTD - } -#endif - -#ifdef NEO_KHZ400 - } else { // 400 KHz - - // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,6,15) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head30:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) - "rjmp .+0" "\n\t" // 2 nop nop (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "nop" "\n\t" // 1 nop (T = 15) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) - "rjmp .+0" "\n\t" // 2 nop nop (T = 19) - "dec %[bit]" "\n\t" // 1 bit-- (T = 20) - "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) - "rjmp .+0" "\n\t" // 2 nop nop (T = 24) - "rjmp .+0" "\n\t" // 2 nop nop (T = 26) - "rjmp .+0" "\n\t" // 2 nop nop (T = 28) - "rjmp head30" "\n\t" // 2 -> head30 (next bit out) - "nextbyte30:" "\n\t" // (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) - "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); - } -#endif // NEO_KHZ400 - -// 16 MHz(ish) AVR -------------------------------------------------------- -#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - - // WS2811 and WS2812 have different hi/lo duty cycles; this is - // similar but NOT an exact copy of the prior 400-on-8 code. - - // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL - // ST instructions: ^ ^ ^ (T=0,5,13) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "dec %[bit]" "\n\t" // 1 bit-- (T = 5) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef NEO_KHZ400 - } else { // 400 KHz - - // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. - - // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,8,20) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head40:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "rjmp .+0" "\n\t" // 2 nop nop (T = 8) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp .+0" "\n\t" // 2 nop nop (T = 20) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) - "dec %[bit]" "\n\t" // 1 bit-- (T = 25) - "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) - "nop" "\n\t" // 1 nop (T = 28) - "rjmp .+0" "\n\t" // 2 nop nop (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "rjmp .+0" "\n\t" // 2 nop nop (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "rjmp .+0" "\n\t" // 2 nop nop (T = 38) - "rjmp head40" "\n\t" // 2 -> head40 (next bit out) - "nextbyte40:" "\n\t" // (T = 27) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) - "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - } -#endif // NEO_KHZ400 - -#else - #error "CPU SPEED NOT SUPPORTED" -#endif // end F_CPU ifdefs on __AVR__ - -// END AVR ---------------------------------------------------------------- - - -#elif defined(__arm__) - -// ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due --------------------------- - -#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 -#define CYCLES_800_T0H (F_CPU / 4000000) -#define CYCLES_800_T1H (F_CPU / 1250000) -#define CYCLES_800 (F_CPU / 800000) -#define CYCLES_400_T0H (F_CPU / 2000000) -#define CYCLES_400_T1H (F_CPU / 833333) -#define CYCLES_400 (F_CPU / 400000) - - uint8_t *p = pixels, - *end = p + numBytes, pix, mask; - volatile uint8_t *set = portSetRegister(pin), - *clr = portClearRegister(pin); - uint32_t cyc; - - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - cyc = ARM_DWT_CYCCNT + CYCLES_800; - while(p < end) { - pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); - cyc = ARM_DWT_CYCCNT; - *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); - } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); - } - *clr = 1; - } - } - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); -#ifdef NEO_KHZ400 - } else { // 400 kHz bitstream - cyc = ARM_DWT_CYCCNT + CYCLES_400; - while(p < end) { - pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - cyc = ARM_DWT_CYCCNT; - *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); - } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); - } - *clr = 1; - } - } - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - } -#endif // NEO_KHZ400 - -#elif defined(__MKL26Z64__) // Teensy-LC - -#if F_CPU == 48000000 - uint8_t *p = pixels, - pix, count, dly, - bitmask = digitalPinToBitMask(pin); - volatile uint8_t *reg = portSetRegister(pin); - uint32_t num = numBytes; - asm volatile( - "L%=_begin:" "\n\t" - "ldrb %[pix], [%[p], #0]" "\n\t" - "lsl %[pix], #24" "\n\t" - "movs %[count], #7" "\n\t" - "L%=_loop:" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_loop_one" "\n\t" - "L%=_loop_zero:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0L" "\n\t" - "b L%=_next" "\n\t" - "L%=_loop_one:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_next:" "\n\t" - "sub %[count], #1" "\n\t" - "bne L%=_loop" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_last_one" "\n\t" - "L%=_last_zero:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_last_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #10" "\n\t" - "L%=_last_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0L" "\n\t" - "b L%=_repeat" "\n\t" - "L%=_last_one:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_last_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #1" "\n\t" - "L%=_last_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_repeat:" "\n\t" - "add %[p], #1" "\n\t" - "sub %[num], #1" "\n\t" - "bne L%=_begin" "\n\t" - "L%=_done:" "\n\t" - : [p] "+r" (p), - [pix] "=&r" (pix), - [count] "=&r" (count), - [dly] "=&r" (dly), - [num] "+r" (num) - : [bitmask] "r" (bitmask), - [reg] "r" (reg) - ); -#else -#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" -#endif // F_CPU == 48000000 - -#elif defined(__SAMD21G18A__) // Arduino Zero - - // Tried this with a timer/counter, couldn't quite get adequate - // resolution. So yay, you get a load of goofball NOPs... - - uint8_t *ptr, *end, p, bitMask, portNum; - uint32_t pinMask; - - portNum = g_APinDescription[pin].ulPort; - pinMask = 1ul << g_APinDescription[pin].ulPin; - ptr = pixels; - end = ptr + numBytes; - p = *ptr++; - bitMask = 0x80; - - volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg), - *clr = &(PORT->Group[portNum].OUTCLR.reg); - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - for(;;) { - *set = pinMask; - asm("nop; nop; nop; nop; nop; nop; nop; nop;"); - if(p & bitMask) { - asm("nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop;"); - *clr = pinMask; - } else { - *clr = pinMask; - asm("nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop;"); - } - if(bitMask >>= 1) { - asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;"); - } else { - if(ptr >= end) break; - p = *ptr++; - bitMask = 0x80; - } - } -#ifdef NEO_KHZ400 - } else { // 400 KHz bitstream - for(;;) { - *set = pinMask; - asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); - if(p & bitMask) { - asm("nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop;"); - *clr = pinMask; - } else { - *clr = pinMask; - asm("nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop;"); - } - asm("nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;" - "nop; nop; nop; nop; nop; nop; nop; nop;"); - if(bitMask >>= 1) { - asm("nop; nop; nop; nop; nop; nop; nop;"); - } else { - if(ptr >= end) break; - p = *ptr++; - bitMask = 0x80; - } - } - } -#endif - - -#else // Other ARM architecture -- Presumed Arduino Due - - #define SCALE VARIANT_MCK / 2UL / 1000000UL - #define INST (2UL * F_CPU / VARIANT_MCK) - #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) - #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) - - int pinMask, time0, time1, period, t; - Pio *port; - volatile WoReg *portSet, *portClear, *timeValue, *timeReset; - uint8_t *p, *end, pix, mask; - - pmc_set_writeprotect(false); - pmc_enable_periph_clk((uint32_t)TC3_IRQn); - TC_Configure(TC1, 0, - TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); - TC_Start(TC1, 0); - - pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into - port = g_APinDescription[pin].pPort; // declarations above. Want to - portSet = &(port->PIO_SODR); // burn a few cycles after - portClear = &(port->PIO_CODR); // starting timer to minimize - timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. - timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); - p = pixels; - end = p + numBytes; - pix = *p++; - mask = 0x80; - -#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { -#endif - time0 = TIME_800_0; - time1 = TIME_800_1; - period = PERIOD_800; -#ifdef NEO_KHZ400 - } else { // 400 KHz bitstream - time0 = TIME_400_0; - time1 = TIME_400_1; - period = PERIOD_400; - } -#endif - - for(t = time0;; t = time0) { - if(pix & mask) t = time1; - while(*timeValue < period); - *portSet = pinMask; - *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; - while(*timeValue < t); - *portClear = pinMask; - if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes - if(p >= end) break; // idle time to minimize inter-byte delays. - pix = *p++; - mask = 0x80; - } - } - while(*timeValue < period); // Wait for last bit - TC_Stop(TC1, 0); - -#endif // end Due - -// END ARM ---------------------------------------------------------------- - - -#elif defined(ESP8266) - -// ESP8266 ---------------------------------------------------------------- - - // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution - espShow(pin, pixels, numBytes, is800KHz); - -#elif defined(__ARDUINO_ARC__) - -// Arduino 101 ----------------------------------------------------------- - -#define NOPx7{ __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); } - - PinDescription *pindesc = &g_APinDescription[pin]; - register uint32_t loop = 8 * numBytes; // one loop to handle all bytes and all bits - register uint8_t *p = pixels; - register uint32_t currByte = (uint32_t) (*p); - register uint32_t currBit = 0x80 & currByte; - register uint32_t bitCounter = 0; - register uint32_t first = 1; - - // The loop is unusual. Very first iteration puts all the way LOW to the wire - - // constant LOW does not affect NEOPIXEL, so there is no visible effect displayed. - // During that very first iteration CPU caches instructions in the loop. - // Because of the caching process, "CPU slows down". NEOPIXEL pulse is very time sensitive - // that's why we let the CPU cache first and we start regular pulse from 2nd iteration - if (pindesc->ulGPIOType == SS_GPIO) { - register uint32_t reg = pindesc->ulGPIOBase + SS_GPIO_SWPORTA_DR; - uint32_t reg_val = __builtin_arc_lr((volatile uint32_t)reg); - register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); - register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); - - loop += 1; // include first, special iteration - while(loop--) { - if(!first) { - currByte <<= 1; - bitCounter++; - } - - // 1 is >550ns high and >450ns low; 0 is 200..500ns high and >450ns low - __builtin_arc_sr(first ? reg_bit_low : reg_bit_high, (volatile uint32_t)reg); - if(currBit) { // ~400ns HIGH (740ns overall) - NOPx7 - NOPx7 - } - // ~340ns HIGH - NOPx7 - __builtin_arc_nop(); - - // 820ns LOW; per spec, max allowed low here is 5000ns */ - __builtin_arc_sr(reg_bit_low, (volatile uint32_t)reg); - NOPx7 - NOPx7 - - if(bitCounter >= 8) { - bitCounter = 0; - currByte = (uint32_t) (*++p); - } - - currBit = 0x80 & currByte; - first = 0; - } - } else if(pindesc->ulGPIOType == SOC_GPIO) { - register uint32_t reg = pindesc->ulGPIOBase + SOC_GPIO_SWPORTA_DR; - uint32_t reg_val = MMIO_REG_VAL(reg); - register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); - register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); - - loop += 1; // include first, special iteration - while(loop--) { - if(!first) { - currByte <<= 1; - bitCounter++; - } - MMIO_REG_VAL(reg) = first ? reg_bit_low : reg_bit_high; - if(currBit) { // ~430ns HIGH (740ns overall) - NOPx7 - NOPx7 - __builtin_arc_nop(); - } - // ~310ns HIGH - NOPx7 - - // 850ns LOW; per spec, max allowed low here is 5000ns */ - MMIO_REG_VAL(reg) = reg_bit_low; - NOPx7 - NOPx7 - - if(bitCounter >= 8) { - bitCounter = 0; - currByte = (uint32_t) (*++p); - } - - currBit = 0x80 & currByte; - first = 0; - } - } - -#endif - - -// END ARCHITECTURE SELECT ------------------------------------------------ - - - interrupts(); - endTime = micros(); // Save EOD time for latch on next call -} - -// Set the output pin number -void Adafruit_NeoPixel::setPin(uint8_t p) { - if(begun && (pin >= 0)) pinMode(pin, INPUT); - if(p >= 0) { - pin = p; - if(begun) { - pinMode(p, OUTPUT); - digitalWrite(p, LOW); - } -#ifdef __AVR__ - port = portOutputRegister(digitalPinToPort(p)); - pinMask = digitalPinToBitMask(p); -#endif - } -} - -// Set pixel color from separate R,G,B components: -void Adafruit_NeoPixel::setPixelColor( - uint16_t n, uint8_t r, uint8_t g, uint8_t b) { - - if(n < numLEDs) { - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - uint8_t *p; - if(wOffset == rOffset) { // Is an RGB-type strip - p = &pixels[n * 3]; // 3 bytes per pixel - } else { // Is a WRGB-type strip - p = &pixels[n * 4]; // 4 bytes per pixel - p[wOffset] = 0; // But only R,G,B passed -- set W to 0 - } - p[rOffset] = r; // R,G,B always stored - p[gOffset] = g; - p[bOffset] = b; - } -} - -// Set pixel color from 'packed' 32-bit RGB color: -void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { - if(n < numLEDs) { - uint8_t *p, - r = (uint8_t)(c >> 16), - g = (uint8_t)(c >> 8), - b = (uint8_t)c; - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - if(wOffset == rOffset) { - p = &pixels[n * 3]; - } else { - p = &pixels[n * 4]; - uint8_t w = (uint8_t)(c >> 24); - p[wOffset] = brightness ? ((w * brightness) >> 8) : w; - } - p[rOffset] = r; - p[gOffset] = g; - p[bOffset] = b; - } -} - -// Convert separate R,G,B into packed 32-bit RGB color. -// Packed format is always RGB, regardless of LED strand color order. -uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { - return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} - -// Convert separate R,G,B,W into packed 32-bit WRGB color. -// Packed format is always WRGB, regardless of LED strand color order. -uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { - return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} - -// Query color from previously-set pixel (returns packed 32-bit RGB value) -uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { - if(n >= numLEDs) return 0; // Out of bounds, return no color. - - uint8_t *p; - - if(wOffset == rOffset) { // Is RGB-type device - p = &pixels[n * 3]; - if(brightness) { - // Stored color was decimated by setBrightness(). Returned value - // attempts to scale back to an approximation of the original 24-bit - // value used when setting the pixel color, but there will always be - // some error -- those bits are simply gone. Issue is most - // pronounced at low brightness levels. - return (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | - (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | - ( (uint32_t)(p[bOffset] << 8) / brightness ); - } else { - // No brightness adjustment has been made -- return 'raw' color - return ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; - } - } else { // Is RGBW-type device - p = &pixels[n * 4]; - if(brightness) { // Return scaled color - return (((uint32_t)(p[wOffset] << 8) / brightness) << 24) | - (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | - (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | - ( (uint32_t)(p[bOffset] << 8) / brightness ); - } else { // Return raw color - return ((uint32_t)p[wOffset] << 24) | - ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; - } - } -} - -// Returns pointer to pixels[] array. Pixel data is stored in device- -// native format and is not translated here. Application will need to be -// aware of specific pixel data format and handle colors appropriately. -uint8_t *Adafruit_NeoPixel::getPixels(void) const { - return pixels; -} - -uint16_t Adafruit_NeoPixel::numPixels(void) const { - return numLEDs; -} - -// Adjust output brightness; 0=darkest (off), 255=brightest. This does -// NOT immediately affect what's currently displayed on the LEDs. The -// next call to show() will refresh the LEDs at this level. However, -// this process is potentially "lossy," especially when increasing -// brightness. The tight timing in the WS2811/WS2812 code means there -// aren't enough free cycles to perform this scaling on the fly as data -// is issued. So we make a pass through the existing color data in RAM -// and scale it (subsequent graphics commands also work at this -// brightness level). If there's a significant step up in brightness, -// the limited number of steps (quantization) in the old data will be -// quite visible in the re-scaled version. For a non-destructive -// change, you'll need to re-render the full strip data. C'est la vie. -void Adafruit_NeoPixel::setBrightness(uint8_t b) { - // Stored brightness value is different than what's passed. - // This simplifies the actual scaling math later, allowing a fast - // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, - // adding 1 here may (intentionally) roll over...so 0 = max brightness - // (color values are interpreted literally; no scaling), 1 = min - // brightness (off), 255 = just below max brightness. - uint8_t newBrightness = b + 1; - if(newBrightness != brightness) { // Compare against prior value - // Brightness has changed -- re-scale existing data in RAM - uint8_t c, - *ptr = pixels, - oldBrightness = brightness - 1; // De-wrap old brightness value - uint16_t scale; - if(oldBrightness == 0) scale = 0; // Avoid /0 - else if(b == 255) scale = 65535 / oldBrightness; - else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; - for(uint16_t i=0; i> 8; - } - brightness = newBrightness; - } -} - -//Return the brightness value -uint8_t Adafruit_NeoPixel::getBrightness(void) const { - return brightness - 1; -} - -void Adafruit_NeoPixel::clear() { - memset(pixels, 0, numBytes); -} diff --git a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h deleted file mode 100644 index c32e3bf0..00000000 --- a/libraries/Adafruit_NeoPixel/Adafruit_NeoPixel.h +++ /dev/null @@ -1,179 +0,0 @@ -/*-------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel 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 3 of - the License, or (at your option) any later version. - - NeoPixel 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 NeoPixel. If not, see - . - --------------------------------------------------------------------*/ - -#ifndef ADAFRUIT_NEOPIXEL_H -#define ADAFRUIT_NEOPIXEL_H - -#if (ARDUINO >= 100) - #include -#else - #include - #include -#endif - -// The order of primary colors in the NeoPixel data stream can vary -// among device types, manufacturers and even different revisions of -// the same item. The third parameter to the Adafruit_NeoPixel -// constructor encodes the per-pixel byte offsets of the red, green -// and blue primaries (plus white, if present) in the data stream -- -// the following #defines provide an easier-to-use named version for -// each permutation. e.g. NEO_GRB indicates a NeoPixel-compatible -// device expecting three bytes per pixel, with the first byte -// containing the green value, second containing red and third -// containing blue. The in-memory representation of a chain of -// NeoPixels is the same as the data-stream order; no re-ordering of -// bytes is required when issuing data to the chain. - -// Bits 5,4 of this value are the offset (0-3) from the first byte of -// a pixel to the location of the red color byte. Bits 3,2 are the -// green offset and 1,0 are the blue offset. If it is an RGBW-type -// device (supporting a white primary in addition to R,G,B), bits 7,6 -// are the offset to the white byte...otherwise, bits 7,6 are set to -// the same value as 5,4 (red) to indicate an RGB (not RGBW) device. -// i.e. binary representation: -// 0bWWRRGGBB for RGBW devices -// 0bRRRRGGBB for RGB - -// RGB NeoPixel permutations; white and red offsets are always same -// Offset: W R G B -#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2)) -#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1)) -#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2)) -#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1)) -#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0)) -#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0)) - -// RGBW NeoPixel permutations; all 4 offsets are distinct -// Offset: W R G B -#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3)) -#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2)) -#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3)) -#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2)) -#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1)) -#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1)) - -#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3)) -#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2)) -#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3)) -#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2)) -#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1)) -#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1)) - -#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3)) -#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2)) -#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3)) -#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2)) -#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1)) -#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1)) - -#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0)) -#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0)) -#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0)) -#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0)) -#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0)) -#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0)) - -// Add NEO_KHZ400 to the color order value to indicate a 400 KHz -// device. All but the earliest v1 NeoPixels expect an 800 KHz data -// stream, this is the default if unspecified. Because flash space -// is very limited on ATtiny devices (e.g. Trinket, Gemma), v1 -// NeoPixels aren't handled by default on those chips, though it can -// be enabled by removing the ifndef/endif below -- but code will be -// bigger. Conversely, can disable the NEO_KHZ400 line on other MCUs -// to remove v1 support and save a little space. - -#define NEO_KHZ800 0x0000 // 800 KHz datastream -#ifndef __AVR_ATtiny85__ -#define NEO_KHZ400 0x0100 // 400 KHz datastream -#endif - -// If 400 KHz support is enabled, the third parameter to the constructor -// requires a 16-bit value (in order to select 400 vs 800 KHz speed). -// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value -// is sufficient to encode pixel color order, saving some space. - -#ifdef NEO_KHZ400 -typedef uint8_t neoPixelType; -#else -typedef uint16_t neoPixelType; -#endif - -class Adafruit_NeoPixel { - - public: - - // Constructor: number of LEDs, pin number, LED type - Adafruit_NeoPixel(uint16_t n, uint8_t p=6, neoPixelType t=NEO_GRB + NEO_KHZ800); - Adafruit_NeoPixel(void); - ~Adafruit_NeoPixel(); - - void - begin(void), - show(void), - setPin(uint8_t p), - setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), - setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w), - setPixelColor(uint16_t n, uint32_t c), - setBrightness(uint8_t), - clear(), - updateLength(uint16_t n), - updateType(neoPixelType t); - uint8_t - *getPixels(void) const, - getBrightness(void) const; - uint16_t - numPixels(void) const; - static uint32_t - Color(uint8_t r, uint8_t g, uint8_t b), - Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); - uint32_t - getPixelColor(uint16_t n) const; - inline bool - canShow(void) { return (micros() - endTime) >= 50L; } - - private: - - boolean -#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled... - is800KHz, // ...true if 800 KHz pixels -#endif - begun; // true if begin() previously called - uint16_t - numLEDs, // Number of RGB LEDs in strip - numBytes; // Size of 'pixels' buffer below (3 or 4 bytes/pixel) - int8_t - pin; // Output pin number (-1 if not yet set) - uint8_t - brightness, - *pixels, // Holds LED color values (3 or 4 bytes each) - rOffset, // Index of red byte within each 3- or 4-byte pixel - gOffset, // Index of green byte - bOffset, // Index of blue byte - wOffset; // Index of white byte (same as rOffset if no white) - uint32_t - endTime; // Latch timing reference -#ifdef __AVR__ - volatile uint8_t - *port; // Output PORT register - uint8_t - pinMask; // Output PORT bitmask -#endif - -}; - -#endif // ADAFRUIT_NEOPIXEL_H diff --git a/libraries/Adafruit_NeoPixel/COPYING b/libraries/Adafruit_NeoPixel/COPYING deleted file mode 100644 index 7dcf8e8a..00000000 --- a/libraries/Adafruit_NeoPixel/COPYING +++ /dev/null @@ -1,794 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - - -LGPL ADDENDUM: - - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/libraries/Adafruit_NeoPixel/README.md b/libraries/Adafruit_NeoPixel/README.md deleted file mode 100644 index 7aaaa206..00000000 --- a/libraries/Adafruit_NeoPixel/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Adafruit NeoPixel Library [![Build Status](https://travis-ci.org/adafruit/Adafruit_NeoPixel.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_NeoPixel) - -Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield]. - -After downloading, rename folder to 'Adafruit_NeoPixel' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch. - -[flora]: http://adafruit.com/products/1060 -[strip]: http://adafruit.com/products/1138 -[pixel]: http://adafruit.com/products/1312 -[stick]: http://adafruit.com/products/1426 -[shield]: http://adafruit.com/products/1430 diff --git a/libraries/Adafruit_NeoPixel/esp8266.c b/libraries/Adafruit_NeoPixel/esp8266.c deleted file mode 100644 index 1ae3ba0f..00000000 --- a/libraries/Adafruit_NeoPixel/esp8266.c +++ /dev/null @@ -1,67 +0,0 @@ -// This is a mash-up of the Due show() code + insights from Michael Miller's -// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus -// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. - -#ifdef ESP8266 - -#include -#include - -static uint32_t _getCycleCount(void) __attribute__((always_inline)); -static inline uint32_t _getCycleCount(void) { - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); - return ccount; -} - -void ICACHE_RAM_ATTR espShow( - uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { - -#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us -#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us -#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit -#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS -#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us -#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit - - uint8_t *p, *end, pix, mask; - uint32_t t, time0, time1, period, c, startTime, pinMask; - - pinMask = _BV(pin); - p = pixels; - end = p + numBytes; - pix = *p++; - mask = 0x80; - startTime = 0; - -#ifdef NEO_KHZ400 - if(is800KHz) { -#endif - time0 = CYCLES_800_T0H; - time1 = CYCLES_800_T1H; - period = CYCLES_800; -#ifdef NEO_KHZ400 - } else { // 400 KHz bitstream - time0 = CYCLES_400_T0H; - time1 = CYCLES_400_T1H; - period = CYCLES_400; - } -#endif - - for(t = time0;; t = time0) { - if(pix & mask) t = time1; // Bit high duration - while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high - startTime = c; // Save start time - while(((c = _getCycleCount()) - startTime) < t); // Wait high duration - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low - if(!(mask >>= 1)) { // Next bit/byte - if(p >= end) break; - pix = *p++; - mask = 0x80; - } - } - while((_getCycleCount() - startTime) < period); // Wait for last bit -} - -#endif // ESP8266 diff --git a/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino b/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino deleted file mode 100644 index cf1598a8..00000000 --- a/libraries/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino +++ /dev/null @@ -1,165 +0,0 @@ -// This is a demonstration on how to use an input device to trigger changes on your neo pixels. -// You should wire a momentary push button to connect from ground to a digital IO pin. When you -// press the button it will change to a new pixel animation. Note that you need to press the -// button once to start the first animation! - -#include - -#define BUTTON_PIN 2 // Digital IO pin connected to the button. This will be - // driven with a pull-up resistor so the switch should - // pull the pin to ground momentarily. On a high -> low - // transition the button press logic will execute. - -#define PIXEL_PIN 6 // Digital IO pin connected to the NeoPixels. - -#define PIXEL_COUNT 16 - -// Parameter 1 = number of pixels in strip, neopixel stick has 8 -// Parameter 2 = pin number (most are valid) -// Parameter 3 = pixel type flags, add together as needed: -// NEO_RGB Pixels are wired for RGB bitstream -// NEO_GRB Pixels are wired for GRB bitstream, correct for neopixel stick -// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels) -// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick -Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); - -bool oldState = HIGH; -int showType = 0; - -void setup() { - pinMode(BUTTON_PIN, INPUT_PULLUP); - strip.begin(); - strip.show(); // Initialize all pixels to 'off' -} - -void loop() { - // Get current button state. - bool newState = digitalRead(BUTTON_PIN); - - // Check if state changed from high to low (button press). - if (newState == LOW && oldState == HIGH) { - // Short delay to debounce button. - delay(20); - // Check if button is still low after debounce. - newState = digitalRead(BUTTON_PIN); - if (newState == LOW) { - showType++; - if (showType > 9) - showType=0; - startShow(showType); - } - } - - // Set the last button state to the old state. - oldState = newState; -} - -void startShow(int i) { - switch(i){ - case 0: colorWipe(strip.Color(0, 0, 0), 50); // Black/off - break; - case 1: colorWipe(strip.Color(255, 0, 0), 50); // Red - break; - case 2: colorWipe(strip.Color(0, 255, 0), 50); // Green - break; - case 3: colorWipe(strip.Color(0, 0, 255), 50); // Blue - break; - case 4: theaterChase(strip.Color(127, 127, 127), 50); // White - break; - case 5: theaterChase(strip.Color(127, 0, 0), 50); // Red - break; - case 6: theaterChase(strip.Color( 0, 0, 127), 50); // Blue - break; - case 7: rainbow(20); - break; - case 8: rainbowCycle(20); - break; - case 9: theaterChaseRainbow(50); - break; - } -} - -// Fill the dots one after the other with a color -void colorWipe(uint32_t c, uint8_t wait) { - for(uint16_t i=0; i -#ifdef __AVR__ - #include -#endif - -// Which pin on the Arduino is connected to the NeoPixels? -// On a Trinket or Gemma we suggest changing this to 1 -#define PIN 6 - -// How many NeoPixels are attached to the Arduino? -#define NUMPIXELS 16 - -// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. -// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest -// example for more information on possible values. -Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); - -int delayval = 500; // delay for half a second - -void setup() { - // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket -#if defined (__AVR_ATtiny85__) - if (F_CPU == 16000000) clock_prescale_set(clock_div_1); -#endif - // End of trinket special code - - pixels.begin(); // This initializes the NeoPixel library. -} - -void loop() { - - // For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one. - - for(int i=0;i -#ifdef __AVR__ - #include -#endif - -#define PIN 6 - -// Parameter 1 = number of pixels in strip -// Parameter 2 = Arduino pin number (most are valid) -// Parameter 3 = pixel type flags, add together as needed: -// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) -// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) -// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) -// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) -Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); - -// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across -// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input -// and minimize distance between Arduino and first pixel. Avoid connecting -// on a live circuit...if you must, connect GND first. - -void setup() { - // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket - #if defined (__AVR_ATtiny85__) - if (F_CPU == 16000000) clock_prescale_set(clock_div_1); - #endif - // End of trinket special code - - - strip.begin(); - strip.show(); // Initialize all pixels to 'off' -} - -void loop() { - // Some example procedures showing how to display to the pixels: - colorWipe(strip.Color(255, 0, 0), 50); // Red - colorWipe(strip.Color(0, 255, 0), 50); // Green - colorWipe(strip.Color(0, 0, 255), 50); // Blue - // Send a theater pixel chase in... - theaterChase(strip.Color(127, 127, 127), 50); // White - theaterChase(strip.Color(127, 0, 0), 50); // Red - theaterChase(strip.Color(0, 0, 127), 50); // Blue - - rainbow(20); - rainbowCycle(20); - theaterChaseRainbow(50); -} - -// Fill the dots one after the other with a color -void colorWipe(uint32_t c, uint8_t wait) { - for(uint16_t i=0; i -sentence=Arduino library for controlling single-wire-based LED pixels and strip. -paragraph=Arduino library for controlling single-wire-based LED pixels and strip. -category=Display -url=https://github.com/adafruit/Adafruit_NeoPixel -architectures=* From 0d86ead0d4ae870c32c679fca3ef087c83a758fc Mon Sep 17 00:00:00 2001 From: Calvin Park Date: Thu, 3 Dec 2015 11:34:56 -0800 Subject: [PATCH 085/222] Add flashpack to IDE --- boards.txt | 2 ++ platform.txt | 11 ++++++++++- programmers.txt | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/boards.txt b/boards.txt index 903f7c17..38fe0d31 100644 --- a/boards.txt +++ b/boards.txt @@ -28,6 +28,8 @@ arduino_101.build.variant_system_lib=arc32drv_arduino101 arduino_101.build.vid=0x8087 arduino_101.build.pid=0x0AB6 +arduino_101.bootloader.tool=arduino101load + ############################################################## diff --git a/platform.txt b/platform.txt index fcf1d336..ac39c379 100644 --- a/platform.txt +++ b/platform.txt @@ -5,7 +5,7 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=Intel Curie (32-bit) Boards -version=1.0.6 +version=1.0.7 # Arduino 101 compile variables # ---------------------- @@ -99,3 +99,12 @@ tools.arduino101load.upload.params.verbose=verbose tools.arduino101load.upload.params.quiet=quiet tools.arduino101load.upload.pattern="{cmd.path}" "{runtime.tools.arduino101load.path}/x86/bin" {build.path}/{build.project_name}.bin {serial.port} "{upload.verbose}" + +# This is needed to avoid an error on unexistent fields +tools.arduino101load.erase.params.verbose= +tools.arduino101load.erase.params.quiet= +tools.arduino101load.erase.pattern= +tools.arduino101load.bootloader.params.verbose= +tools.arduino101load.bootloader.params.quiet= +tools.arduino101load.bootloader.pattern={runtime.tools.flashpack.path}/flash_dfu.sh +tools.arduino101load.bootloader.pattern.windows={runtime.tools.flashpack.path}/flash_dfu.bat diff --git a/programmers.txt b/programmers.txt index e69de29b..15bded23 100644 --- a/programmers.txt +++ b/programmers.txt @@ -0,0 +1,6 @@ +arduino101fw.name=Arduino/Genuino 101 Firmware Updater +arduino101fw.communication=USB +arduino101fw.protocol= +arduino101fw.program.protocol= +arduino101fw.program.tool=arduino101load +arduino101fw.program.extra_params= From 431fb6fd27bdfbd6aaa97e690f1b162a1e02cb62 Mon Sep 17 00:00:00 2001 From: sys_maker Date: Mon, 22 Aug 2016 12:35:27 -0700 Subject: [PATCH 086/222] Rebuilding libarc32 library Signed-off-by: sys_maker --- variants/arduino_101/libarc32drv_arduino101.a | Bin 488868 -> 496120 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index 9161cd367244a5ff9a034e3bdea6515640dffecf..8b179a8385f95cc3be74936955f88b4eb12a9572 100644 GIT binary patch literal 496120 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%0Dgy82r0wAOXa9j8H3JY~s>tZ8h*`6;4I@7&Zc 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%0DOpGM&w&^ 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 JJ-ehb{{>&+Bu)ST literal 488868 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 z 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

w1*FD4{_U9_yYzF5X-E}_Jd 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%0AegHh`oG$Pbfc6)m-v|9a6I_IH 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 From 10d1056503099431cda97deacabbb2a68f43121e Mon Sep 17 00:00:00 2001 From: Brian Baltz Date: Thu, 25 Aug 2016 12:47:00 -0700 Subject: [PATCH 087/222] Verify BLE FW version on every sketch upload Signed-off-by: Brian Baltz --- platform.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform.txt b/platform.txt index ac39c379..e5493cb2 100644 --- a/platform.txt +++ b/platform.txt @@ -91,6 +91,11 @@ recipe.output.save_file={build.project_name}.{build.variant}.hex recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" recipe.size.regex=^(?:text|ctors|rodata|datas)\s+([0-9]+).* +# BLE firmware check +# ------------------- +tools.arduino101load.ble.fw.string="ATP1BLE000-1541C5635" +tools.arduino101load.ble.fw.position=141312 + # Arc Uploader/Programmers tools # ------------------- tools.arduino101load.cmd.path={runtime.tools.arduino101load.path}/arduino101load/arduino101load @@ -98,7 +103,7 @@ tools.arduino101load.cmd.path={runtime.tools.arduino101load.path}/arduino101load tools.arduino101load.upload.params.verbose=verbose tools.arduino101load.upload.params.quiet=quiet -tools.arduino101load.upload.pattern="{cmd.path}" "{runtime.tools.arduino101load.path}/x86/bin" {build.path}/{build.project_name}.bin {serial.port} "{upload.verbose}" +tools.arduino101load.upload.pattern="{cmd.path}" "{runtime.tools.arduino101load.path}/x86/bin" {build.path}/{build.project_name}.bin {serial.port} "{upload.verbose}" {ble.fw.string} {ble.fw.position} # This is needed to avoid an error on unexistent fields tools.arduino101load.erase.params.verbose= From b329d080469778b7e9c8e0868ab6edba4a7fdf97 Mon Sep 17 00:00:00 2001 From: russmcinnis Date: Tue, 30 Aug 2016 15:56:08 -0700 Subject: [PATCH 088/222] add comment to pulseIn() in the header file to warn programmer about trying to detect high frequencies. --- cores/arduino/wiring_pulse.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cores/arduino/wiring_pulse.h b/cores/arduino/wiring_pulse.h index 62bf4d4c..4af69e02 100644 --- a/cores/arduino/wiring_pulse.h +++ b/cores/arduino/wiring_pulse.h @@ -27,7 +27,10 @@ * \brief Measures the length (in microseconds) of a pulse on the pin; state is HIGH * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds * to 5 minutes in length, but must be called at least a few dozen microseconds - * before the start of the pulse. + * before the start of the pulse. The pulseIn() function is not designed to detect + * high frequencies. The consequences of using this function to detect frequencies + * such as a 100KHz PWM signal could possibly cause a sketch to hang at the + * pulseIn() function call. */ extern uint32_t pulseIn( uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout = 1000000UL ) ; From e084140957ebe2aa0d891c496ced456538c9a1b9 Mon Sep 17 00:00:00 2001 From: Erik Nyquist Date: Wed, 7 Sep 2016 16:02:31 -0700 Subject: [PATCH 089/222] stdlib_noniso.cpp: fix dtostrf() handling of integral portion Checking only for > 10 here (rather than >= 10) means that numbers with a leading '10' in the integral portion generate incorrect strings. --- cores/arduino/stdlib_noniso.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 68c0ba39..7b8a107c 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -221,7 +221,7 @@ char *dtostrf(double number, signed char width, unsigned char prec, char *s) // generate chars for each digit of the integral part i = before; - while (integer > 10) { + while (integer >= 10) { digit = integer % 10; out[(i--) - 1] = ASCII_ZERO + digit; integer /= 10; From d8d2c495b531fda1ffe98cb59f7e35fd948c5bad Mon Sep 17 00:00:00 2001 From: Biagio Montaruli Date: Wed, 7 Sep 2016 13:05:01 +0200 Subject: [PATCH 090/222] Fix for USB virtual serial port in sketches of CurieI2S library Since Arduino/Genuino 101 uses USB native port, wait for the Serial port to open before executing the next lines of code to not lose serial data already sent to the Serial monitor Signed-off-by: Biagio Montaruli --- .../examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino | 6 +++--- .../examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino | 4 ++-- .../CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino | 4 ++-- .../CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino index a41f25f3..ed099fa1 100644 --- a/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_RXCallBack/I2SDMA_RXCallBack.ino @@ -37,8 +37,8 @@ uint32_t loop_count = 0; // record the higher 16 bits of received data uint32_t shift_count = 0; // the position of first non-zero void setup() { - Serial.begin(115200); - while(!Serial); + Serial.begin(115200); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. Serial.println("CurieI2SDMA Rx Callback"); CurieI2SDMA.iniRX(); @@ -119,4 +119,4 @@ void loop() License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- 1301 USA -*/ \ No newline at end of file +*/ diff --git a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino index d39bea36..9ce55501 100644 --- a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino @@ -15,8 +15,8 @@ uint32_t dataBuff[BUFF_SIZE]; uint32_t loop_count = 0; void setup() { - Serial.begin(115200); - while(!Serial); + Serial.begin(115200); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. Serial.println("CurieI2SDMA Tx Callback"); CurieI2SDMA.iniTX(); diff --git a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino index 101d3774..9550ad1f 100644 --- a/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino +++ b/libraries/CurieI2S/examples/I2S_RxCallback/I2S_RxCallback.ino @@ -23,8 +23,8 @@ volatile int count = 0; void setup() { // put your setup code here, to run once: - Serial.begin(115200); - while(!Serial); + Serial.begin(115200); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. Serial.println("CurieI2S Rx Callback Example"); CurieI2S.begin(I2S_44K, I2S_32bit); CurieI2S.setI2SMode(PHILIPS_MODE); diff --git a/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino b/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino index cb3ff7cf..76189db2 100644 --- a/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino +++ b/libraries/CurieI2S/examples/I2S_TxCallback/I2S_TxCallback.ino @@ -6,8 +6,8 @@ void setup() { - Serial.begin(115200); - while(!Serial); + Serial.begin(115200); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. Serial.println("CurieI2S Tx Callback"); CurieI2S.begin(I2S_44K, I2S_32bit); CurieI2S.setI2SMode(PHILIPS_MODE); From 2751995ab29738c708b5b7d109d98cbfc34a09e4 Mon Sep 17 00:00:00 2001 From: Biagio Montaruli Date: Wed, 7 Sep 2016 13:01:32 +0200 Subject: [PATCH 091/222] Fix for USB virtual serial port in sketches of CurieIMU library Since Arduino/Genuino 101 uses USB native port, wait for the Serial port to open before executing the sketch to not lose serial data already sent to the Serial monitor Signed-off-by: Biagio Montaruli --- libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino | 4 ++-- libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino | 4 ++-- libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino | 4 ++-- libraries/CurieIMU/examples/StepCount/StepCount.ino | 3 ++- libraries/CurieIMU/examples/TapDetect/TapDetect.ino | 4 ++-- .../CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino | 4 ++-- .../CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino | 4 ++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino index 36786412..ca88e457 100644 --- a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino +++ b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino @@ -16,8 +16,8 @@ unsigned long interruptsTime = 0; // get the time when free fall event is det void setup() { - Serial.begin(9600); - while(!Serial); // wait for the serial port to open + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. /* Initialise the IMU */ CurieIMU.begin(); diff --git a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino index 2eb8c9ac..400ad461 100644 --- a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino +++ b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino @@ -15,8 +15,8 @@ unsigned long loopTime = 0; // get the time since program started unsigned long interruptsTime = 0; // get the time when motion event is detected void setup() { - Serial.begin(9600); - while(!Serial); // wait for the serial port to open + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. /* Initialise the IMU */ CurieIMU.begin(); diff --git a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino index 3d3bb656..467299a2 100644 --- a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino +++ b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino @@ -13,8 +13,8 @@ boolean blinkState = false; // state of the LED void setup() { - Serial.begin(9600); - + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect.. /* Initialise the IMU */ CurieIMU.begin(); CurieIMU.attachInterrupt(eventCallback); diff --git a/libraries/CurieIMU/examples/StepCount/StepCount.ino b/libraries/CurieIMU/examples/StepCount/StepCount.ino index 386121b0..aafc9483 100644 --- a/libraries/CurieIMU/examples/StepCount/StepCount.ino +++ b/libraries/CurieIMU/examples/StepCount/StepCount.ino @@ -25,7 +25,8 @@ long lastStepCount = 0; // step count on previous polling check boolean blinkState = false; // state of the LED void setup() { - Serial.begin(9600); + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. // pinMode(13, OUTPUT); // intialize the sensor: CurieIMU.begin(); diff --git a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino index d0489a9a..a6c6ede3 100644 --- a/libraries/CurieIMU/examples/TapDetect/TapDetect.ino +++ b/libraries/CurieIMU/examples/TapDetect/TapDetect.ino @@ -11,8 +11,8 @@ #include "CurieIMU.h" void setup() { - Serial.begin(9600); - + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. // Initialise the IMU CurieIMU.begin(); CurieIMU.attachInterrupt(eventCallback); diff --git a/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino index d8c63f4b..12148e84 100644 --- a/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino +++ b/libraries/CurieIMU/examples/TapDoubleDetect/TapDoubleDetect.ino @@ -11,8 +11,8 @@ #include "CurieIMU.h" void setup() { - Serial.begin(9600); - + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. // Initialise the IMU CurieIMU.begin(); CurieIMU.attachInterrupt(eventCallback); diff --git a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino index 56c9b79e..56fc3a9d 100644 --- a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino +++ b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino @@ -11,8 +11,8 @@ boolean ledState = false; // state of the LED void setup() { - Serial.begin(9600); - while(!Serial); // wait for the serial port to open + Serial.begin(9600); // initialize Serial communication + while(!Serial) ; // wait for serial port to connect. /* Initialise the IMU */ CurieIMU.begin(); From f818d7cd360e109c31bc65ed11f0df3b133bc826 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 6 Sep 2016 14:06:34 -0400 Subject: [PATCH 092/222] Make String::move of an invalidated String result in an invalidated String --- cores/arduino/WString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 73a96f9f..ce4e4f85 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -227,7 +227,7 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) void String::move(String &rhs) { if (buffer) { - if (capacity >= rhs.len) { + if (rhs && capacity >= rhs.len) { strcpy(buffer, rhs.buffer); len = rhs.len; rhs.len = 0; From 23ca972371c3bf9db488e948d35b870a1fa52b2c Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Thu, 15 Sep 2016 15:22:35 -0400 Subject: [PATCH 093/222] WString: add `toDouble` (#293) Port of https://github.com/arduino/Arduino/pull/5362 --- cores/arduino/WString.cpp | 9 +++++++-- cores/arduino/WString.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index ce4e4f85..d577e002 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -810,6 +810,11 @@ long String::toInt(void) const float String::toFloat(void) const { - if (buffer) return float(atof(buffer)); - return 0; + return (float)toDouble(); +} + +double String::toDouble(void) const +{ + if (buffer) return atof(buffer); + return 0; } diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 75a3e143..2ff259f8 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -199,6 +199,7 @@ class String // parsing/conversion long toInt(void) const; float toFloat(void) const; + double toDouble(void) const; char * getCSpec(int base, bool issigned, bool islong); protected: From 7dcc0742ef43174547efec5497359d6d80cc6387 Mon Sep 17 00:00:00 2001 From: Biagio Montaruli Date: Sat, 17 Sep 2016 13:45:03 +0200 Subject: [PATCH 094/222] Update bus_scan.ino sketch of Wire library Improve documentation, code formatting and use LED_BUILTIN instead of 13 to control the on-board led connected to digital pin 13 of Arduino/Genuino 101 Signed-off-by: Biagio Montaruli --- libraries/Wire/examples/bus_scan/bus_scan.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/Wire/examples/bus_scan/bus_scan.ino b/libraries/Wire/examples/bus_scan/bus_scan.ino index e816ea79..65fc0946 100644 --- a/libraries/Wire/examples/bus_scan/bus_scan.ino +++ b/libraries/Wire/examples/bus_scan/bus_scan.ino @@ -17,7 +17,7 @@ #include -byte startAddress = 1; // skip reserved address from 0 to 7 +byte startAddress = 1; byte endAddress = 127; void I2CBusScan(byte startAddress, byte endAddress) @@ -36,12 +36,14 @@ void I2CBusScan(byte startAddress, byte endAddress) void setup() { // Initialize pin 13 as an output - onboard LED. - pinMode(13, OUTPUT); + pinMode(LED_BUILTIN, OUTPUT); // join i2c bus (address optional for master) Wire.begin(); + // initialize Serial communication Serial.begin(115200); + // wait for the Serial port to connect. Open the Serial Monitor to continue executing the sketch while(!Serial); } @@ -49,7 +51,7 @@ boolean toggle = false; // state of the LED void loop() { toggle = !toggle; - digitalWrite(13, toggle); + digitalWrite(LED_BUILTIN, toggle); delay(5000); Serial.print("Start I2C Bus Scan from "); @@ -58,7 +60,7 @@ void loop() Serial.print(endAddress); Serial.println("....."); - I2CBusScan( startAddress, endAddress); + I2CBusScan(startAddress, endAddress); Serial.println("\ndone"); } From 4c69f724b9e253c014e118ca87d031929deea7ca Mon Sep 17 00:00:00 2001 From: Sidney Leung Date: Thu, 1 Sep 2016 15:20:32 -0700 Subject: [PATCH 095/222] Added support for Quark I2C interfaces: I2C0 and I2C1. Additions: 1. Ported Quark I2C driver to ARC/CoreLibs, located at system/libarc32_arduino101/drivers. 2. Created the I2C Adapters, located at cores/arduino. Modifications: 1. Platform.h - added number of I2C interface definition. --- cores/arduino/i2c.c | 362 ++++---- cores/arduino/i2c.h | 15 +- cores/arduino/soc_i2c.c | 331 +++++++ cores/arduino/soc_i2c.h | 51 ++ libraries/CurieIMU/src/CurieIMU.cpp | 51 +- libraries/CurieIMU/src/internal/ss_spi.c | 135 --- .../examples/master_reader/master_reader.ino | 8 +- .../examples/master_writer/master_writer.ino | 10 +- libraries/Wire/src/Wire.cpp | 154 ++-- libraries/Wire/src/Wire.h | 9 +- .../common/scss_registers.h | 4 + .../libarc32_arduino101/common/ss_i2c_iface.h | 3 +- .../drivers/intel_qrk_i2c.c | 838 ++++++++++++++++++ .../drivers/intel_qrk_i2c.h | 284 ++++++ .../drivers/soc_i2c_priv.h | 198 +++++ system/libarc32_arduino101/drivers/spi_priv.h | 4 +- system/libarc32_arduino101/drivers/ss_spi.c | 248 ++++++ .../libarc32_arduino101/drivers}/ss_spi.h | 21 +- .../framework/include/platform.h | 1 + variants/arduino_101/libarc32drv_arduino101.a | Bin 496120 -> 0 bytes variants/arduino_101/pins_arduino.h | 2 +- variants/arduino_101/variant.cpp | 12 +- 22 files changed, 2312 insertions(+), 429 deletions(-) create mode 100644 cores/arduino/soc_i2c.c create mode 100644 cores/arduino/soc_i2c.h delete mode 100644 libraries/CurieIMU/src/internal/ss_spi.c create mode 100644 system/libarc32_arduino101/drivers/intel_qrk_i2c.c create mode 100644 system/libarc32_arduino101/drivers/intel_qrk_i2c.h create mode 100644 system/libarc32_arduino101/drivers/soc_i2c_priv.h create mode 100644 system/libarc32_arduino101/drivers/ss_spi.c rename {libraries/CurieIMU/src/internal => system/libarc32_arduino101/drivers}/ss_spi.h (55%) delete mode 100644 variants/arduino_101/libarc32drv_arduino101.a diff --git a/cores/arduino/i2c.c b/cores/arduino/i2c.c index 6b1b0aff..34bf3ecc 100644 --- a/cores/arduino/i2c.c +++ b/cores/arduino/i2c.c @@ -19,208 +19,242 @@ * */ -#include #include "i2c.h" #include "variant.h" #define TIMEOUT_MS 16 -static volatile uint8_t i2c_tx_complete; -static volatile uint8_t i2c_rx_complete; -static volatile uint8_t i2c_err_detect; -static volatile uint32_t i2c_err_source; +static volatile uint8_t i2c_tx_complete[NUM_SS_I2C]; +static volatile uint8_t i2c_rx_complete[NUM_SS_I2C]; +static volatile uint8_t i2c_err_detect[NUM_SS_I2C]; +static volatile uint32_t i2c_err_source[NUM_SS_I2C]; -static volatile uint8_t i2c_slave = 0; +static volatile uint8_t i2c_slave[NUM_SS_I2C]; -static void ss_i2c_rx(uint32_t dev_id) +static void ss_i2c_0_rx(uint32_t dev_id) { - i2c_rx_complete = 1; + i2c_rx_complete[I2C_SENSING_0] = 1; } -static void ss_i2c_tx(uint32_t dev_id) +static void ss_i2c_1_rx(uint32_t dev_id) { - i2c_tx_complete = 1; + i2c_rx_complete[I2C_SENSING_1] = 1; } -static void ss_i2c_err(uint32_t dev_id) +static void ss_i2c_0_tx(uint32_t dev_id) { - i2c_err_detect = 1; - i2c_err_source = dev_id; + i2c_tx_complete[I2C_SENSING_0] = 1; } -static int wait_rx_or_err() +static void ss_i2c_1_tx(uint32_t dev_id) { - uint64_t timeout = TIMEOUT_MS * 200; - while(timeout--) { - if (i2c_err_detect) { - if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) - { - return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address - } - else if (i2c_err_source & I2C_ABRT_TXDATA_NOACK ) - { - return I2C_ERROR_DATA_NOACK; // NACK on transmit of data - } - else - { - return I2C_ERROR_OTHER; // other error - } - } - if (i2c_rx_complete) { - return I2C_OK; - } - delayMicroseconds(10); - } - - return I2C_TIMEOUT; + i2c_tx_complete[I2C_SENSING_1] = 1; } -static int wait_tx_or_err() +static void ss_i2c_0_err(uint32_t dev_id) { - uint64_t timeout = TIMEOUT_MS * 200; - while(timeout--) { - if (i2c_err_detect) { - if (i2c_err_source & I2C_ABRT_7B_ADDR_NOACK ) - { - return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address - } - else if (i2c_err_source & I2C_ABRT_TXDATA_NOACK ) - { - return I2C_ERROR_DATA_NOACK; // NACK on transmit of data - } - else - { - return I2C_ERROR_OTHER; // other error - } - } - if (i2c_tx_complete) { - return I2C_OK; - } - delayMicroseconds(10); - } - return I2C_TIMEOUT; + i2c_err_detect[I2C_SENSING_0] = 1; + i2c_err_source[I2C_SENSING_0] = dev_id; } -static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){ - uint64_t timeout = TIMEOUT_MS * 200; - int ret = 0; - while(timeout--) { - ret = ss_i2c_status(controller_id, no_stop); - if (ret == I2C_OK) { - return I2C_OK; - } - else if (ret == I2C_BUSY) { - delayMicroseconds(10); - } - else - { - return I2C_TIMEOUT - ret; - } - } - return I2C_TIMEOUT - ret; +static void ss_i2c_1_err(uint32_t dev_id) +{ + i2c_err_detect[I2C_SENSING_1] = 1; + i2c_err_source[I2C_SENSING_1] = dev_id; } - -int i2c_openadapter(void) +static int wait_rx_or_err(I2C_CONTROLLER controller_id) { - int ret; - - SET_PIN_MODE(24, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) - SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) - - SET_PIN_PULLUP(24, 1); - SET_PIN_PULLUP(25, 1); - - i2c_cfg_data_t i2c_cfg; - memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); - - i2c_cfg.speed = I2C_SLOW; - i2c_cfg.addressing_mode = I2C_7_Bit; - i2c_cfg.mode_type = I2C_MASTER; - i2c_cfg.cb_tx = ss_i2c_tx; - i2c_cfg.cb_rx = ss_i2c_rx; - i2c_cfg.cb_err = ss_i2c_err; - - i2c_tx_complete = 0; - i2c_rx_complete = 0; - i2c_err_detect = 0; - i2c_err_source = 0; - - ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg); - ss_i2c_clock_enable(I2C_SENSING_0); - ret = wait_dev_ready(I2C_SENSING_0, false); - - return ret; + uint64_t timeout = TIMEOUT_MS * 200; + + while (timeout--) { + if (i2c_err_detect[controller_id]) { + if (i2c_err_source[controller_id] & I2C_ABRT_7B_ADDR_NOACK) { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } else if (i2c_err_source[controller_id] & I2C_ABRT_TXDATA_NOACK) { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } else { + return I2C_ERROR_OTHER; // other error + } + } + if (i2c_rx_complete[controller_id]) { + return I2C_OK; + } + delayMicroseconds(10); + } + + return I2C_TIMEOUT; } -int i2c_openadapter_speed(int i2c_speed) +static int wait_tx_or_err(I2C_CONTROLLER controller_id) { - int ret; - - SET_PIN_MODE(24, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) - SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) - - SET_PIN_PULLUP(24, 1); - SET_PIN_PULLUP(25, 1); - - i2c_cfg_data_t i2c_cfg; - memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); - - i2c_cfg.speed = i2c_speed; - i2c_cfg.addressing_mode = I2C_7_Bit; - i2c_cfg.mode_type = I2C_MASTER; - i2c_cfg.cb_tx = ss_i2c_tx; - i2c_cfg.cb_rx = ss_i2c_rx; - i2c_cfg.cb_err = ss_i2c_err; - - i2c_tx_complete = 0; - i2c_rx_complete = 0; - i2c_err_detect = 0; + uint64_t timeout = TIMEOUT_MS * 200; + + while (timeout--) { + if (i2c_err_detect[controller_id]) { + if (i2c_err_source[controller_id] & I2C_ABRT_7B_ADDR_NOACK) { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } else if (i2c_err_source[controller_id] & I2C_ABRT_TXDATA_NOACK) { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } else { + return I2C_ERROR_OTHER; // other error + } + } + if (i2c_tx_complete[controller_id]) { + return I2C_OK; + } + delayMicroseconds(10); + } + return I2C_TIMEOUT; +} - ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg); - ss_i2c_clock_enable(I2C_SENSING_0); - ret = wait_dev_ready(I2C_SENSING_0, false); +static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop) +{ + uint64_t timeout = TIMEOUT_MS * 200; + int ret = 0; + + while (timeout--) { + ret = ss_i2c_status(controller_id, no_stop); + if (ret == I2C_OK) { + return I2C_OK; + } else if (ret == I2C_BUSY) { + delayMicroseconds(10); + } else { + return I2C_TIMEOUT - ret; + } + } + return I2C_TIMEOUT - ret; +} - return ret; +int i2c_openadapter(I2C_CONTROLLER controller_id) +{ + int ret; + + i2c_cfg_data_t i2c_cfg; + memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); + + i2c_cfg.speed = I2C_SLOW; + i2c_cfg.addressing_mode = I2C_7_Bit; + i2c_cfg.mode_type = I2C_MASTER; + + if (controller_id == I2C_SENSING_0) { + SET_PIN_MODE(24, I2C_MUX_MODE); // SOC PIN (Arduino header pin 18) + SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) + + SET_PIN_PULLUP(24, 1); + SET_PIN_PULLUP(25, 1); + i2c_cfg.cb_tx = ss_i2c_0_tx; + i2c_cfg.cb_rx = ss_i2c_0_rx; + i2c_cfg.cb_err = ss_i2c_0_err; + } else if (controller_id == I2C_SENSING_1) { + SET_PIN_MODE(26, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) + SET_PIN_MODE(27, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) + + SET_PIN_PULLUP(26, 1); + SET_PIN_PULLUP(27, 1); + i2c_cfg.cb_tx = ss_i2c_1_tx; + i2c_cfg.cb_rx = ss_i2c_1_rx; + i2c_cfg.cb_err = ss_i2c_1_err; + } else { + return I2C_ERROR; + } + + i2c_tx_complete[controller_id] = 0; + i2c_rx_complete[controller_id] = 0; + i2c_err_detect[controller_id] = 0; + i2c_err_source[controller_id] = 0; + + ss_i2c_set_config(controller_id, &i2c_cfg); + ss_i2c_clock_enable(controller_id); + ret = wait_dev_ready(controller_id, false); + + return ret; } +int i2c_openadapter_speed(I2C_CONTROLLER controller_id, int i2c_speed) +{ + int ret; + i2c_cfg_data_t i2c_cfg; + memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); + + i2c_cfg.speed = i2c_speed; + i2c_cfg.addressing_mode = I2C_7_Bit; + i2c_cfg.mode_type = I2C_MASTER; + + if (controller_id == I2C_SENSING_0) { + SET_PIN_MODE(24, I2C_MUX_MODE); // SOC PIN (Arduino header pin 18) + SET_PIN_MODE(25, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) + + SET_PIN_PULLUP(24, 1); + SET_PIN_PULLUP(25, 1); + i2c_cfg.cb_tx = ss_i2c_0_tx; + i2c_cfg.cb_rx = ss_i2c_0_rx; + i2c_cfg.cb_err = ss_i2c_0_err; + } else if (controller_id == I2C_SENSING_1) { + SET_PIN_MODE(26, I2C_MUX_MODE); // Rxd SOC PIN (Arduino header pin 18) + SET_PIN_MODE(27, I2C_MUX_MODE); // Txd SOC PIN (Arduino header pin 19) + + SET_PIN_PULLUP(26, 1); + SET_PIN_PULLUP(27, 1); + i2c_cfg.cb_tx = ss_i2c_1_tx; + i2c_cfg.cb_rx = ss_i2c_1_rx; + i2c_cfg.cb_err = ss_i2c_1_err; + } else { + return I2C_ERROR; + } + + i2c_tx_complete[controller_id] = 0; + i2c_rx_complete[controller_id] = 0; + i2c_err_detect[controller_id] = 0; + i2c_err_source[controller_id] = 0; + + ss_i2c_set_config(controller_id, &i2c_cfg); + ss_i2c_clock_enable(controller_id); + ret = wait_dev_ready(controller_id, false); + + return ret; +} -void i2c_setslave(uint8_t addr) +void i2c_setslave(I2C_CONTROLLER controller_id, uint8_t addr) { - i2c_slave = addr; - return; + i2c_slave[controller_id] = addr; + return; } -int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop) +int i2c_writebytes(I2C_CONTROLLER controller_id, uint8_t *bytes, uint8_t length, + bool no_stop) { - int ret; - - i2c_tx_complete = 0; - i2c_err_detect = 0; - i2c_err_source = 0; - ss_i2c_transfer(I2C_SENSING_0, bytes, length, 0, 0, i2c_slave, no_stop); - ret = wait_tx_or_err(); - if (ret) - return ret; - ret = wait_dev_ready(I2C_SENSING_0, no_stop); - if (ret) - return ret; - return length; + int ret; + + i2c_tx_complete[controller_id] = 0; + i2c_err_detect[controller_id] = 0; + i2c_err_source[controller_id] = 0; + ss_i2c_transfer(controller_id, bytes, length, 0, 0, + i2c_slave[controller_id], no_stop); + ret = wait_tx_or_err(controller_id); + if (ret) + return ret; + ret = wait_dev_ready(controller_id, no_stop); + if (ret) + return ret; + return length; } -int i2c_readbytes(uint8_t *buf, int length, bool no_stop) +int i2c_readbytes(I2C_CONTROLLER controller_id, uint8_t *buf, int length, + bool no_stop) { - int ret; - - i2c_rx_complete = 0; - i2c_err_detect = 0; - i2c_err_source = 0; - ss_i2c_transfer(I2C_SENSING_0, 0, 0, buf, length, i2c_slave, no_stop); - ret = wait_rx_or_err(); - if (ret) - return ret; - ret = wait_dev_ready(I2C_SENSING_0, no_stop); - if (ret) - return ret; - return length; + int ret; + + i2c_rx_complete[controller_id] = 0; + i2c_err_detect[controller_id] = 0; + i2c_err_source[controller_id] = 0; + ss_i2c_transfer(controller_id, 0, 0, buf, length, i2c_slave[controller_id], + no_stop); + ret = wait_rx_or_err(controller_id); + if (ret) + return ret; + ret = wait_dev_ready(controller_id, no_stop); + if (ret) + return ret; + return length; } diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index f73906fa..870cb5c8 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -23,13 +23,16 @@ #define i2c_h #include +#include +#include "ss_i2c_iface.h" + #ifdef __cplusplus extern "C"{ #endif #define I2C_OK 0 #define I2C_TIMEOUT -10 -#define I2C_ERROR -11 +#define I2C_ERROR -20 /* Qi, 2016. */ #define I2C_ERROR_ADDRESS_NOACK (-2) #define I2C_ERROR_DATA_NOACK (-3) #define I2C_ERROR_OTHER (-4) @@ -37,11 +40,11 @@ extern "C"{ #define I2C_ABRT_7B_ADDR_NOACK (1 << 0) #define I2C_ABRT_TXDATA_NOACK (1 << 3) -int i2c_openadapter(void); -int i2c_openadapter_speed(int); -void i2c_setslave(uint8_t addr); -int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop); -int i2c_readbytes(uint8_t *buf, int length, bool no_stop); +int i2c_openadapter(I2C_CONTROLLER controller_id); +int i2c_openadapter_speed(I2C_CONTROLLER controller_id, int i2c_speed); +void i2c_setslave(I2C_CONTROLLER controller_id, uint8_t addr); +int i2c_writebytes(I2C_CONTROLLER controller_id, uint8_t *bytes, uint8_t length, bool no_stop); +int i2c_readbytes(I2C_CONTROLLER controller_id, uint8_t *buf, int length, bool no_stop); #ifdef __cplusplus } diff --git a/cores/arduino/soc_i2c.c b/cores/arduino/soc_i2c.c new file mode 100644 index 00000000..50ca7b48 --- /dev/null +++ b/cores/arduino/soc_i2c.c @@ -0,0 +1,331 @@ +/* + * soc_i2c.c - i2c library layer + * + * Copyright (C) 2015, 2016 Intel Corporation + * + * 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 + * + */ + +#include +#include "intel_qrk_i2c.h" +#include "variant.h" +#include "soc_i2c.h" +#include "i2c.h" + +#define TIMEOUT_MS 16 + +static volatile uint8_t soc_i2c_master_tx_complete[NUM_SOC_I2C]; +static volatile uint8_t soc_i2c_master_rx_complete[NUM_SOC_I2C]; +static volatile uint8_t soc_i2c_err_detect[NUM_SOC_I2C]; +static volatile uint32_t soc_i2c_err_source[NUM_SOC_I2C]; + +static volatile uint32_t soc_i2c_slave_address[NUM_SOC_I2C] = {0, 0}; + +static void soc_i2c0_master_rx_callback(uint32_t dev_id) +{ + soc_i2c_master_rx_complete[SOC_I2C_0] = 1; +} + +static void soc_i2c1_master_rx_callback(uint32_t dev_id) +{ + soc_i2c_master_rx_complete[SOC_I2C_1] = 1; +} + +static void soc_i2c0_master_tx_callback(uint32_t dev_id) +{ + soc_i2c_master_tx_complete[SOC_I2C_0] = 1; +} + +static void soc_i2c1_master_tx_callback(uint32_t dev_id) +{ + soc_i2c_master_tx_complete[SOC_I2C_1] = 1; +} + +static void soc_i2c0_err_callback(uint32_t dev_id) +{ + soc_i2c_err_detect[SOC_I2C_0] = 1; + soc_i2c_err_source[SOC_I2C_0] = dev_id; +} + +static void soc_i2c1_err_callback(uint32_t dev_id) +{ + soc_i2c_err_detect[SOC_I2C_1] = 1; + soc_i2c_err_source[SOC_I2C_1] = dev_id; +} + +static void (*soc_i2c0_slave_rx_user_callback)(int, void *) = NULL; +static void *soc_i2c0_slave_rx_user_cb_data_ptr = NULL; + +static void (*soc_i2c1_slave_rx_user_callback)(int, void *) = NULL; +static void *soc_i2c1_slave_rx_user_cb_data_ptr = NULL; + +static void (*soc_i2c0_slave_tx_user_callback)(void *) = NULL; +static void *soc_i2c0_slave_tx_user_cb_data_ptr = NULL; + +static void (*soc_i2c1_slave_tx_user_callback)(void *) = NULL; +static void *soc_i2c1_slave_tx_user_cb_data_ptr = NULL; + +static void soc_i2c0_slave_rx_callback(uint32_t bytes) +{ + if (soc_i2c0_slave_rx_user_callback) { + soc_i2c0_slave_rx_user_callback((int)bytes, soc_i2c0_slave_rx_user_cb_data_ptr); + } +} + +static void soc_i2c1_slave_rx_callback(uint32_t bytes) +{ + if (soc_i2c1_slave_rx_user_callback) { + soc_i2c1_slave_rx_user_callback((int)bytes, soc_i2c1_slave_rx_user_cb_data_ptr); + } +} + +static void soc_i2c0_slave_tx_callback(uint32_t bytes) +{ + if (soc_i2c0_slave_tx_user_callback) { + soc_i2c0_slave_tx_user_callback(soc_i2c0_slave_tx_user_cb_data_ptr); + } +} + +static void soc_i2c1_slave_tx_callback(uint32_t bytes) +{ + if (soc_i2c1_slave_tx_user_callback) { + soc_i2c1_slave_tx_user_callback(soc_i2c1_slave_tx_user_cb_data_ptr); + } +} + +void soc_i2c_slave_set_rx_user_callback(SOC_I2C_CONTROLLER controller_id, void (*onReceiveCallback)(int, void *), void *callerDataPtr) +{ + if (controller_id == SOC_I2C_0) { + soc_i2c0_slave_rx_user_callback = onReceiveCallback; + soc_i2c0_slave_rx_user_cb_data_ptr = callerDataPtr; + } else { + soc_i2c1_slave_rx_user_callback = onReceiveCallback; + soc_i2c1_slave_rx_user_cb_data_ptr = callerDataPtr; + } +} + +void soc_i2c_slave_set_tx_user_callback(SOC_I2C_CONTROLLER controller_id, void (*onRequestCallback)(void *), void *callerDataPtr) +{ + if (controller_id == SOC_I2C_0) { + soc_i2c0_slave_tx_user_callback = onRequestCallback; + soc_i2c0_slave_tx_user_cb_data_ptr = callerDataPtr; + } else { + soc_i2c1_slave_tx_user_callback = onRequestCallback; + soc_i2c1_slave_tx_user_cb_data_ptr = callerDataPtr; + } +} + +static int soc_i2c_master_wait_rx_or_err(SOC_I2C_CONTROLLER controller_id) +{ + uint64_t timeout = TIMEOUT_MS * 200; + while (timeout--) { + if (soc_i2c_err_detect[controller_id]) { + if (soc_i2c_err_source[controller_id] & + (I2C_ABRT_7B_ADDR_NOACK | I2C_ABRT_10ADDR1_NOACK | I2C_ABRT_10ADDR2_NOACK)) { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } + else if (soc_i2c_err_source[controller_id] & I2C_ABRT_TXDATA_NOACK) { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } else { + return I2C_ERROR_OTHER; // other error + } + } + if (soc_i2c_master_rx_complete[controller_id]) { + return I2C_OK; + } + delayMicroseconds(10); + } + return I2C_TIMEOUT; +} + +static int soc_i2c_master_wait_tx_or_err(SOC_I2C_CONTROLLER controller_id) +{ + uint64_t timeout = TIMEOUT_MS * 200; + while (timeout--) { + if (soc_i2c_err_detect[controller_id]) { + if (soc_i2c_err_source[controller_id] & + (I2C_ABRT_7B_ADDR_NOACK | I2C_ABRT_10ADDR1_NOACK | I2C_ABRT_10ADDR2_NOACK)) { + return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address + } + else if (soc_i2c_err_source[controller_id] & I2C_ABRT_TXDATA_NOACK) { + return I2C_ERROR_DATA_NOACK; // NACK on transmit of data + } else { + return I2C_ERROR_OTHER; // other error + } + } + if (soc_i2c_master_tx_complete[controller_id]) { + return I2C_OK; + } + delayMicroseconds(10); + } + return I2C_TIMEOUT; +} + +static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id, + bool no_stop) +{ + uint64_t timeout = TIMEOUT_MS * 200; + int ret = 0; + while (timeout--) { + ret = soc_i2c_status(controller_id, no_stop); + if (ret == I2C_OK) { + return I2C_OK; + } + if (ret == I2C_BUSY) { + delayMicroseconds(10); + } + } + return I2C_TIMEOUT - ret; +} + +int soc_i2c_open_adapter(SOC_I2C_CONTROLLER controller_id, uint32_t address, int i2c_speed, int i2c_addr_mode) +{ + int ret = 0; + + if (controller_id == SOC_I2C_0) { + SET_PIN_MODE(20, I2C_MUX_MODE); + SET_PIN_MODE(21, I2C_MUX_MODE); + + SET_PIN_PULLUP(20, 1); + SET_PIN_PULLUP(21, 1); + } else { + SET_PIN_MODE(22, I2C_MUX_MODE); + SET_PIN_MODE(23, I2C_MUX_MODE); + + SET_PIN_PULLUP(22, 1); + SET_PIN_PULLUP(23, 1); + } + + i2c_cfg_data_t i2c_cfg; + memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); + + i2c_cfg.speed = i2c_speed; + i2c_cfg.addressing_mode = i2c_addr_mode; + if (address) { + i2c_cfg.mode_type = I2C_SLAVE; + if (controller_id == SOC_I2C_0) { + i2c_cfg.cb_err = soc_i2c0_err_callback; + i2c_cfg.cb_rx = soc_i2c0_slave_rx_callback; + i2c_cfg.cb_tx = soc_i2c0_slave_tx_callback; + } else { + i2c_cfg.cb_err = soc_i2c1_err_callback; + i2c_cfg.cb_rx = soc_i2c1_slave_rx_callback; + i2c_cfg.cb_tx = soc_i2c1_slave_tx_callback; + } + } else { + i2c_cfg.mode_type = I2C_MASTER; + + if (controller_id == SOC_I2C_0) { + i2c_cfg.cb_tx = soc_i2c0_master_tx_callback; + i2c_cfg.cb_rx = soc_i2c0_master_rx_callback; + i2c_cfg.cb_err = soc_i2c0_err_callback; + } else { + i2c_cfg.cb_tx = soc_i2c1_master_tx_callback; + i2c_cfg.cb_rx = soc_i2c1_master_rx_callback; + i2c_cfg.cb_err = soc_i2c1_err_callback; + } + soc_i2c_master_tx_complete[controller_id] = 0; + soc_i2c_master_rx_complete[controller_id] = 0; + } + i2c_cfg.slave_adr = address; + soc_i2c_err_detect[controller_id] = 0; + soc_i2c_err_source[controller_id] = 0; + + soc_i2c_set_config(controller_id, &i2c_cfg); + soc_i2c_clock_enable(controller_id); + + ret = soc_i2c_wait_dev_ready(controller_id, false); + + return ret; +} + +void soc_i2c_close_adapter(SOC_I2C_CONTROLLER controller_id) +{ + soc_i2c_deconfig(controller_id); + soc_i2c_clock_disable(controller_id); + + if (controller_id == SOC_I2C_0) { + SET_PIN_MODE(20, GPIO_MUX_MODE); + SET_PIN_MODE(21, GPIO_MUX_MODE); + } else { + SET_PIN_MODE(22, GPIO_MUX_MODE); + SET_PIN_MODE(23, GPIO_MUX_MODE); + } + + return; +} + +void soc_i2c_set_speed(SOC_I2C_CONTROLLER controller_id, uint32_t speed) +{ + soc_i2c_set_transfer_speed(controller_id, speed); +} + +void soc_i2c_set_address_mode(SOC_I2C_CONTROLLER controller_id, uint32_t mode) +{ + soc_i2c_set_transfer_mode(controller_id, mode); +} + +void soc_i2c_master_set_slave_address(SOC_I2C_CONTROLLER controller_id, uint32_t addr) +{ + soc_i2c_slave_address[controller_id] = addr; + return; +} + +void soc_i2c_slave_set_rx_user_buffer(SOC_I2C_CONTROLLER controller_id, uint8_t *buffer, uint8_t length) +{ + soc_i2c_slave_enable_rx(controller_id, buffer, length); +} + +void soc_i2c_slave_set_tx_user_buffer(SOC_I2C_CONTROLLER controller_id, uint8_t *buffer, uint8_t length) +{ + soc_i2c_slave_enable_tx(controller_id, buffer, length); +} + +int soc_i2c_master_witebytes(SOC_I2C_CONTROLLER controller_id, uint8_t *buf, uint8_t length, bool no_stop) +{ + int ret; + + soc_i2c_master_tx_complete[controller_id] = 0; + soc_i2c_err_detect[controller_id] = 0; + soc_i2c_err_source[controller_id] = 0; + soc_i2c_master_transfer(controller_id, buf, length, 0, 0, + soc_i2c_slave_address[controller_id], no_stop); + ret = soc_i2c_master_wait_tx_or_err(controller_id); + if (ret) + return ret; + ret = soc_i2c_wait_dev_ready(controller_id, no_stop); + if (ret) + return ret; + return length; +} + +int soc_i2c_master_readbytes(SOC_I2C_CONTROLLER controller_id, uint8_t *buf, int length, bool no_stop) +{ + int ret; + + soc_i2c_master_rx_complete[controller_id] = 0; + soc_i2c_err_detect[controller_id] = 0; + soc_i2c_err_source[controller_id] = 0; + soc_i2c_master_transfer(controller_id, 0, 0, buf, length, + soc_i2c_slave_address[controller_id], no_stop); + ret = soc_i2c_master_wait_rx_or_err(controller_id); + if (ret) + return ret; + ret = soc_i2c_wait_dev_ready(controller_id, no_stop); + if (ret) + return ret; + return length; +} diff --git a/cores/arduino/soc_i2c.h b/cores/arduino/soc_i2c.h new file mode 100644 index 00000000..989f9d1a --- /dev/null +++ b/cores/arduino/soc_i2c.h @@ -0,0 +1,51 @@ +/* + * soc_i2c.h + * + * Copyright (c) 2016 Intel Corporation + * + * 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +#ifndef soc_i2c_h_ +#define soc_i2c_h_ + +#include +#include +#include "intel_qrk_i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_ABRT_10ADDR1_NOACK (1 << 1) +#define I2C_ABRT_10ADDR2_NOACK (1 << 2) + +int soc_i2c_open_adapter(SOC_I2C_CONTROLLER controller_id, uint32_t address, int i2c_speed, int i2c_addr_mode); +void soc_i2c_close_adapter(SOC_I2C_CONTROLLER controller_id); +void soc_i2c_set_speed(SOC_I2C_CONTROLLER controller_id, uint32_t speed); +void soc_i2c_set_address_mode(SOC_I2C_CONTROLLER controller_id, uint32_t mode); +void soc_i2c_master_set_slave_address(SOC_I2C_CONTROLLER controller_id, uint32_t addr); +int soc_i2c_master_witebytes(SOC_I2C_CONTROLLER controller_id, uint8_t *bytes, uint8_t length, bool no_stop); +int soc_i2c_master_readbytes(SOC_I2C_CONTROLLER controller_id, uint8_t *buf, int length, bool no_stop); + void soc_i2c_slave_set_rx_user_callback(SOC_I2C_CONTROLLER controller_id, void (*onReceiveCallback)(int, void *), void *callerDataPtr); +void soc_i2c_slave_set_tx_user_callback(SOC_I2C_CONTROLLER controller_id, void (*onRequestCallback)(void *), void *callerDataPtr); +void soc_i2c_slave_set_rx_user_buffer(SOC_I2C_CONTROLLER controller_id, uint8_t *buffer, uint8_t length); +void soc_i2c_slave_set_tx_user_buffer(SOC_I2C_CONTROLLER controller_id, uint8_t *buffer, uint8_t length); + +#ifdef __cplusplus +} +#endif +#endif /* soc_i2c_h */ diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index 635f9026..94dc4f80 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -18,7 +18,7 @@ */ #include "CurieIMU.h" -#include "internal/ss_spi.h" +#include "ss_spi.h" #include "interrupt.h" #define CURIE_IMU_CHIP_ID 0xD1 @@ -34,14 +34,7 @@ */ bool CurieIMUClass::begin() { - /* Configure pin-mux settings on the Intel Curie module to - * enable SPI mode usage */ - SET_PIN_MODE(35, QRK_PMUX_SEL_MODEA); // SPI1_SS_MISO - SET_PIN_MODE(36, QRK_PMUX_SEL_MODEA); // SPI1_SS_MOSI - SET_PIN_MODE(37, QRK_PMUX_SEL_MODEA); // SPI1_SS_SCK - SET_PIN_MODE(38, QRK_PMUX_SEL_MODEA); // SPI1_SS_CS_B[0] - - ss_spi_init(); + ss_spi_init(SPI_SENSING_1, 2000, SPI_BUSMODE_0, SPI_8_BIT, SPI_SE_1); /* Perform a dummy read from 0x7f to switch to spi interface */ uint8_t dummy_reg = 0x7F; @@ -59,14 +52,14 @@ bool CurieIMUClass::begin() void CurieIMUClass::end() { - ss_spi_disable(); + ss_spi_disable(SPI_SENSING_1); } int CurieIMUClass::getGyroRate() { int rate; - switch(BMI160Class::getGyroRate()) { + switch (BMI160Class::getGyroRate()) { case BMI160_GYRO_RATE_25HZ: rate = 25; break; @@ -133,7 +126,7 @@ float CurieIMUClass::getAccelerometerRate() { float rate; - switch(BMI160Class::getAccelRate()) { + switch (BMI160Class::getAccelRate()) { case BMI160_ACCEL_RATE_25_2HZ: rate = 12.5; break; @@ -875,8 +868,6 @@ float CurieIMUClass::getMotionDetectionDuration() int bmiDuration = BMI160Class::getMotionDetectionDuration(); return (bmiDuration / getAccelerometerRate()); - - } void CurieIMUClass::setMotionDetectionDuration(float duration) { @@ -1454,7 +1445,7 @@ void CurieIMUClass::enableInterrupt(int feature, bool enabled) setIntZeroMotionEnabled(enabled); break; - case CURIE_IMU_TAP: + case CURIE_IMU_TAP: setIntTapEnabled(enabled); break; @@ -1493,7 +1484,7 @@ bool CurieIMUClass::interruptsEnabled(int feature) case CURIE_IMU_ZERO_MOTION: return getIntZeroMotionEnabled(); - case CURIE_IMU_TAP: + case CURIE_IMU_TAP: return getIntTapEnabled(); case CURIE_IMU_DOUBLE_TAP: @@ -1562,12 +1553,13 @@ float CurieIMUClass::convertRaw(int16_t raw, float range_abs) /* Input range will be -32768 to 32767 * Output range must be -range_abs to range_abs */ - val = (float) raw; + val = (float)raw; slope = (range_abs * 2.0f) / BMI160_SENSOR_RANGE; return -(range_abs) + slope * (val + BMI160_SENSOR_LOW); } -void CurieIMUClass::readMotionSensor(int& ax, int& ay, int& az, int& gx, int& gy, int& gz) +void CurieIMUClass::readMotionSensor(int &ax, int &ay, int &az, int &gx, + int &gy, int &gz) { short sax, say, saz, sgx, sgy, sgz; @@ -1581,8 +1573,8 @@ void CurieIMUClass::readMotionSensor(int& ax, int& ay, int& az, int& gx, int& gy gz = sgz; } -void CurieIMUClass::readMotionSensorScaled(float& ax, float& ay, float& az, - float& gx, float& gy, float& gz) +void CurieIMUClass::readMotionSensorScaled(float &ax, float &ay, float &az, + float &gx, float &gy, float &gz) { int16_t sax, say, saz, sgx, sgy, sgz; @@ -1596,7 +1588,7 @@ void CurieIMUClass::readMotionSensorScaled(float& ax, float& ay, float& az, gz = convertRaw(sgz, gyro_range); } -void CurieIMUClass::readAccelerometer(int& x, int& y, int& z) +void CurieIMUClass::readAccelerometer(int &x, int &y, int &z) { short sx, sy, sz; @@ -1607,7 +1599,7 @@ void CurieIMUClass::readAccelerometer(int& x, int& y, int& z) z = sz; } -void CurieIMUClass::readAccelerometerScaled(float& x, float& y, float& z) +void CurieIMUClass::readAccelerometerScaled(float &x, float &y, float &z) { int16_t sx, sy, sz; @@ -1618,7 +1610,7 @@ void CurieIMUClass::readAccelerometerScaled(float& x, float& y, float& z) z = convertRaw(sz, accel_range); } -void CurieIMUClass::readGyro(int& x, int& y, int& z) +void CurieIMUClass::readGyro(int &x, int &y, int &z) { short sx, sy, sz; @@ -1629,7 +1621,7 @@ void CurieIMUClass::readGyro(int& x, int& y, int& z) z = sz; } -void CurieIMUClass::readGyroScaled(float& x, float& y, float& z) +void CurieIMUClass::readGyroScaled(float &x, float &y, float &z) { int16_t sx, sy, sz; @@ -1650,7 +1642,7 @@ int CurieIMUClass::readAccelerometer(int axis) return getAccelerationZ(); } - return 0; + return 0; } float CurieIMUClass::readAccelerometerScaled(int axis) @@ -1783,7 +1775,8 @@ bool CurieIMUClass::stepsDetected() * to use for accessing device registers. This implementation uses the SPI * bus on the Intel Curie module to communicate with the BMI160. */ -int CurieIMUClass::serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt) +int CurieIMUClass::serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, + unsigned rx_cnt) { int flags, status; @@ -1795,7 +1788,7 @@ int CurieIMUClass::serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, unsigne * - avoid delays in SPI transfer due to unrelated interrupts */ flags = interrupt_lock(); - status = ss_spi_xfer(buf, tx_cnt, rx_cnt); + status = ss_spi_xfer(SPI_SENSING_1, buf, tx_cnt, rx_cnt); interrupt_unlock(flags); return status; @@ -1831,8 +1824,8 @@ void CurieIMUClass::attachInterrupt(void (*callback)(void)) cfg.gpio_cb = bmi160_pin1_isr; soc_gpio_set_config(SOC_GPIO_AON, BMI160_GPIN_AON_PIN, &cfg); - setInterruptMode(1); // Active-Low - setInterruptDrive(0); // Push-Pull + setInterruptMode(1); // Active-Low + setInterruptDrive(0); // Push-Pull setInterruptLatch(BMI160_LATCH_MODE_10_MS); // 10ms pulse setIntEnabled(true); } diff --git a/libraries/CurieIMU/src/internal/ss_spi.c b/libraries/CurieIMU/src/internal/ss_spi.c deleted file mode 100644 index 5905aad5..00000000 --- a/libraries/CurieIMU/src/internal/ss_spi.c +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************* - * - * Synopsys DesignWare Sensor and Control IP Subsystem IO Software Driver and - * documentation (hereinafter, "Software") is an Unsupported proprietary work - * of Synopsys, Inc. unless otherwise expressly agreed to in writing between - * Synopsys and you. - * - * The Software IS NOT an item of Licensed Software or Licensed Product under - * any End User Software License Agreement or Agreement for Licensed Product - * with Synopsys or any supplement thereto. You are permitted to use and - * redistribute this Software in source and binary forms, with or without - * modification, provided that redistributions of source code must retain this - * notice. You may not view, use, disclose, copy or distribute this file or - * any information contained herein except pursuant to this license grant from - * Synopsys. If you do not agree with this notice, including the disclaimer - * below, then you are not authorized to use the Software. - * - * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - ******************************************************************************/ - -/******************************************************************************* - * - * Modifications Copyright (c) 2015, Intel Corporation. All rights reserved. - * - ******************************************************************************/ - -#include - -#include "eiaextensions.h" -#include "spi_priv.h" -#include "common_spi.h" -#include "soc_gpio.h" -#include "portable.h" - -#include "ss_spi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SPI_FIFO_DEPTH (8UL) - -#define SS_SPI_REG_WRITE(reg, x) \ - WRITE_ARC_REG((x), AR_IO_SPI_MST1_CTRL + (reg)) -#define SS_SPI_REG_READ(reg) \ - READ_ARC_REG(AR_IO_SPI_MST1_CTRL + (reg)) - -void ss_spi_init() -{ - SET_ARC_BIT(AR_IO_CREG_MST0_CTRL, CREG_CLK_CTRL_SPI1); - - /* disable SPI controller */ - SS_SPI_REG_WRITE(SPIEN, SPI_DISABLE); - /* enable controller clock to allow register writes */ - SS_SPI_REG_WRITE(CTRL, SPI_CLK_ENABLED); - - /* SPI Mode-0, 8-bit frame size */ - SS_SPI_REG_WRITE(CTRL, SPI_CLK_ENABLED | SPI_8_BIT | (SPI_EPROM_RD << 8)); - SS_SPI_REG_WRITE(TIMING, 16); /* 2MHz (32MHz/16) */ - - /* Disable interrupts */ - SS_SPI_REG_WRITE(INTR_MASK, SPI_DISABLE_INT); -} - -void ss_spi_disable() -{ - /* gate SPI controller clock */ - SS_SPI_REG_WRITE(CTRL, 0); -} - -static inline -void spi_transmit(uint8_t *buf, size_t count, boolean_t waitCompletion) { - while (count--) - SS_SPI_REG_WRITE(DR, *buf++ | SPI_PUSH_DATA); - /* Wait for transfer to complete */ - if (waitCompletion) - while ((SS_SPI_REG_READ(TXFLR) > 0) || (SS_SPI_REG_READ(SR) & SPI_STATUS_BUSY)); -} - -static inline -void spi_receive(uint8_t *buf, size_t count) { - while (count) { - if (SS_SPI_REG_READ(RXFLR) > 0) { - SS_SPI_REG_WRITE(DR, SPI_POP_DATA); - *buf++ = SS_SPI_REG_READ(DR); - count--; - } - SS_SPI_REG_READ(RXFLR); /* Extra read of RXFLR, apparently necessary */ - } -} - -/* Polling-based SPI transfer to allow use within an ISR */ -int ss_spi_xfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt) -{ - uint32_t ctrl = SS_SPI_REG_READ(CTRL) & SPI_NDF_SET_MASK & SPI_TMOD_SET_MASK; - - if (rx_cnt == 0) - ctrl |= (SPI_TX_ONLY << 8); - else if (tx_cnt == 0) - ctrl |= (SPI_RX_ONLY << 8) | ((rx_cnt - 1) << 16); - else - ctrl |= (SPI_EPROM_RD << 8) | ((rx_cnt - 1) << 16); - SS_SPI_REG_WRITE(CTRL, ctrl); - - // Assert the slave-select and start the SPI transfer - SS_SPI_REG_WRITE(SPIEN, (SPI_SE_1 << 4) | SPI_ENABLE); - - if (tx_cnt) - spi_transmit(buf, tx_cnt, !(rx_cnt)); // No wait for TX-RX transfers - else - SS_SPI_REG_WRITE(DR, SPI_PUSH_DATA | 0x56); // start rx-only transfer - - if (rx_cnt) - spi_receive(buf, rx_cnt); - - // De-assert the slave-select and end the SPI transfer - SS_SPI_REG_WRITE(SPIEN, 0); - - return 0; -} - -#ifdef __cplusplus -} -#endif diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index b6748b18..5b43c4b8 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -14,20 +14,20 @@ void setup() { - Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); // start serial for output + while(!Serial); + Wire.begin(); // join i2c bus (address optional for master) } void loop() { - Wire.requestFrom(8, 6,false); // request 6 bytes from slave device #8 + Wire.requestFrom(8, 6, true); // request 6 bytes from slave device #8 while (Wire.available()) // slave may send less than requested { char c = Wire.read(); // receive a byte as character - Serial.print(c); // print the character + Serial.print(c, HEX); // print the character Serial.println(); - } delay(500); diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index 5304fd81..1b883504 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -16,6 +16,7 @@ void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); + while(!Serial); } byte x = 1; @@ -26,9 +27,12 @@ void loop() //Wire.write("x is "); // sends five bytes Wire.write(x); // sends one byte int result = Wire.endTransmission(); // stop transmitting - Serial.println(); - Serial.print("x = "); - Serial.print(x); + if (result == 0) + { + Serial.println(); + Serial.print("x = "); + Serial.print(x); + } x++; delay(500); } diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index b2b557f6..2f8601f7 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -22,90 +22,91 @@ */ extern "C" { -#include #include +#include } #include "Wire.h" #include "variant.h" - -TwoWire::TwoWire(void) : rxBufferIndex(0), rxBufferLength(0), - txBufferLength(0), init_status(-1) +TwoWire::TwoWire(I2C_CONTROLLER _controller_id) + : rxBufferIndex(0), rxBufferLength(0), init_status(-1), + controller_id(_controller_id) { - // Empty + // Empty } void TwoWire::begin(void) { - init_status = i2c_openadapter(); + init_status = i2c_openadapter(controller_id); } void TwoWire::begin(int i2c_speed) { - init_status = i2c_openadapter_speed(i2c_speed); + init_status = i2c_openadapter_speed(controller_id, i2c_speed); } void TwoWire::setClock(long speed) { - if(speed == 400000L) { - init_status = i2c_openadapter_speed(I2C_SPEED_FAST); - } else if(speed == 100000L) { - init_status = i2c_openadapter_speed(I2C_SPEED_SLOW); - } else if(speed == I2C_SPEED_FAST) { - init_status = i2c_openadapter_speed(I2C_SPEED_FAST); - }else { - init_status = i2c_openadapter(); + if (speed == 400000L) { + init_status = i2c_openadapter_speed(controller_id, I2C_SPEED_FAST); + } else if (speed == 100000L) { + init_status = i2c_openadapter_speed(controller_id, I2C_SPEED_SLOW); + } else if (speed == I2C_SPEED_FAST) { + init_status = i2c_openadapter_speed(controller_id, I2C_SPEED_FAST); + } else { + init_status = i2c_openadapter(controller_id); } } -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { - int ret; - if (quantity > BUFFER_LENGTH) - quantity = BUFFER_LENGTH; + int ret; + if (quantity > BUFFER_LENGTH) + quantity = BUFFER_LENGTH; - /* Set slave address via ioctl */ - i2c_setslave(address); - ret = i2c_readbytes(rxBuffer, quantity, !sendStop); - if (ret < 0) { - return 0; - } - // set rx buffer iterator vars - rxBufferIndex = 0; - rxBufferLength = quantity; + /* Set slave address via ioctl */ + i2c_setslave(controller_id, address); + ret = i2c_readbytes(controller_id, rxBuffer, quantity, !sendStop); + if (ret < 0) { + return 0; + } + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = quantity; - return quantity; + return quantity; } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); } uint8_t TwoWire::requestFrom(int address, int quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); } uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop); + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); } void TwoWire::beginTransmission(uint8_t address) { - if (init_status < 0) - return; - // set slave address - i2c_setslave(address); - // reset transmit buffer - txBufferLength = 0; + if (init_status < 0) + return; + // set slave address + i2c_setslave(controller_id, address); + // reset transmit buffer + txBufferLength = 0; } void TwoWire::beginTransmission(int address) { - beginTransmission((uint8_t) address); + beginTransmission((uint8_t)address); } // @@ -123,22 +124,23 @@ void TwoWire::beginTransmission(int address) // uint8_t TwoWire::endTransmission(uint8_t sendStop) { - int err; - // transmit buffer (blocking) - if (txBufferLength >= 1) { - err = i2c_writebytes(txBuffer, txBufferLength, !sendStop); - } else { - uint8_t temp = 0; - // Workaround: I2C bus scan is currently implemented by reading, - // so set the read length to 0 to inform the lower I2C driver that we are doing bus scan - err = i2c_readbytes(&temp, 0, 0); - } - // empty buffer - txBufferLength = 0; - if (err < 0) { - return -err; - } - return 0; // success + int err; + // transmit buffer (blocking) + if (txBufferLength >= 1) { + err = + i2c_writebytes(controller_id, txBuffer, txBufferLength, !sendStop); + } else { + uint8_t temp = 0; + // Workaround: I2C bus scan is currently implemented by reading, + // so set the read length to 0 to inform the lower I2C driver that we are doing bus scan + err = i2c_readbytes(controller_id, &temp, 0, 0); + } + // empty buffer + txBufferLength = 0; + if (err < 0) { + return -err; + } + return 0; // success } // This provides backwards compatibility with the original @@ -146,52 +148,52 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) // uint8_t TwoWire::endTransmission(void) { - return endTransmission(true); + return endTransmission(true); } size_t TwoWire::write(uint8_t data) { - if (txBufferLength >= BUFFER_LENGTH) - return 0; - txBuffer[txBufferLength++] = data; - return 1; + if (txBufferLength >= BUFFER_LENGTH) + return 0; + txBuffer[txBufferLength++] = data; + return 1; } size_t TwoWire::write(const uint8_t *data, size_t quantity) { - for (size_t i = 0; i < quantity; ++i) { - if (txBufferLength >= BUFFER_LENGTH) - return i; - txBuffer[txBufferLength++] = data[i]; - } - return quantity; + for (size_t i = 0; i < quantity; ++i) { + if (txBufferLength >= BUFFER_LENGTH) + return i; + txBuffer[txBufferLength++] = data[i]; + } + return quantity; } int TwoWire::available(void) { - return rxBufferLength - rxBufferIndex; + return rxBufferLength - rxBufferIndex; } int TwoWire::read(void) { - if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex++]; - return -1; + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex++]; + return -1; } int TwoWire::peek(void) { - if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex]; - return -1; + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex]; + return -1; } void TwoWire::flush(void) { - // Do nothing, use endTransmission(..) to force - // data transfer. + // Do nothing, use endTransmission(..) to force + // data transfer. } // Preinstantiate Objects ////////////////////////////////////////////////////// -TwoWire Wire = TwoWire(); +TwoWire Wire = TwoWire(I2C_SENSING_0); diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index f1488f41..a18e1f19 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -23,6 +23,7 @@ #include "Stream.h" #include "variant.h" +#include "ss_i2c_iface.h" #define BUFFER_LENGTH 32 #define I2C_SPEED_SLOW 1 @@ -30,9 +31,9 @@ class TwoWire : public Stream { public: - TwoWire(void); - void begin(); - void begin(int); + TwoWire(I2C_CONTROLLER _controller_id); + void begin(void); + void begin(int speed); void setClock(long speed); void beginTransmission(uint8_t); void beginTransmission(int); @@ -67,6 +68,8 @@ class TwoWire : public Stream { uint8_t txBufferLength; int init_status; + + I2C_CONTROLLER controller_id; }; #if WIRE_INTERFACES_COUNT > 0 diff --git a/system/libarc32_arduino101/common/scss_registers.h b/system/libarc32_arduino101/common/scss_registers.h index 600459a4..33f08633 100644 --- a/system/libarc32_arduino101/common/scss_registers.h +++ b/system/libarc32_arduino101/common/scss_registers.h @@ -456,4 +456,8 @@ #define I2C0_CLK_GATE_MASK 0x00080004 #define I2C1_CLK_GATE_MASK 0x00100008 #define I2S_CLK_GATE_MASK 0x00200200 +#define SS_SPI0_CLK_GATE_MASK 0x00000008 +#define SS_SPI1_CLK_GATE_MASK 0x00000010 +#define SS_I2C0_CLK_GATE_MASK 0x00000002 +#define SS_I2C1_CLK_GATE_MASK 0x00000004 #endif /* SCSS_REGISTERS_H_ */ diff --git a/system/libarc32_arduino101/common/ss_i2c_iface.h b/system/libarc32_arduino101/common/ss_i2c_iface.h index ee5e8a8b..e85e3ae7 100644 --- a/system/libarc32_arduino101/common/ss_i2c_iface.h +++ b/system/libarc32_arduino101/common/ss_i2c_iface.h @@ -48,7 +48,8 @@ typedef enum { I2C_SENSING_0 = 0, /*!< Sensing I2C controller 0, accessibly by Sensor Subsystem Core only */ - I2C_SENSING_1 /*!< Sensing I2C controller 1, accessible by Sensor Subsystem Core only */ + I2C_SENSING_1, /*!< Sensing I2C controller 1, accessible by Sensor Subsystem Core only */ + NUM_SS_I2C /*!< Number of Sensor Subsystem I2C controllers */ } I2C_CONTROLLER; #ifdef __cplusplus diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c new file mode 100644 index 00000000..1b9cb274 --- /dev/null +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c @@ -0,0 +1,838 @@ +/* -------------------------------------------------------------------- +** +** Synopsys DesignWare AMBA Software Driver Kit and +** documentation (hereinafter, "Software") is an Unsupported +** proprietary work of Synopsys, Inc. unless otherwise expressly +** agreed to in writing between Synopsys and you. +** +** The Software IS NOT an item of Licensed Software or Licensed +** Product under any End User Software License Agreement or Agreement +** for Licensed Product with Synopsys or any supplement thereto. You +** are permitted to use and redistribute this Software in source and +** binary forms, with or without modification, provided that +** redistributions of source code must retain this notice. You may not +** view, use, disclose, copy or distribute this file or any information +** contained herein except pursuant to this license grant from Synopsys. +** If you do not agree with this notice, including the disclaimer +** below, then you are not authorized to use the Software. +** +** THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" +** BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +** FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL +** SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +** OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +** +** -------------------------------------------------------------------- +*/ + +/**************************************************************************************** + * + * Modifications Copyright (c) 2015, Intel Corporation. All rights reserved. + * + ***************************************************************************************/ + +#include "intel_qrk_i2c.h" + +#include +#include +#include +#include + +#include "clk_system.h" +#include "platform.h" +#include "portable.h" +#include "scss_registers.h" + +#include "soc_i2c_priv.h" + +typedef uint8_t DATA_BUFF; +typedef void (*MY_ISR)(); + +typedef struct { + uint32_t BASE; // base address of device register set + + volatile uint8_t + state; /* last direction of transfer - used by ISR to call right + callback */ + uint16_t fifo_depth; + /* Transmitted bytes. */ + uint32_t total_read_bytes; + uint32_t total_write_bytes; + uint32_t tx_len; + uint32_t rx_len; + uint32_t rx_tx_len; // tx_len + rx_len + uint8_t *i2c_write_buff; + uint8_t *i2c_read_buff; + + volatile uint8_t tx_watermark; /* TX watermark level */ + volatile uint8_t rx_watermark; /* RX watermark level */ + + /* Callbacks */ + MY_ISR ISR; /* pointer to ISR function */ + i2c_callback tx_cb; /* Write callback */ + i2c_callback rx_cb; /* Read callback */ + i2c_callback err_cb; /* Error callback */ + uint32_t cb_rx_data; /* pass data back for callbacks above (aligned to + callbacks) */ + uint32_t cb_tx_data; + uint32_t cb_err_data; + + uint8_t send_restart; + uint8_t send_stop; + + struct clk_gate_info_s clk_gate_info; /*!< clock gate data */ + + /* Config params */ + I2C_SPEED speed; + I2C_ADDR_MODE addr_mode; + I2C_MODE_TYPE mode; + uint32_t slave_addr; + /* Slave specific */ + SOC_I2C_SLAVE_MODE slave_mode; +} i2c_internal_data_t; + +/* device config keeper */ +static i2c_internal_data_t devices[2]; + +static void soc_i2c_abort_transfer(i2c_internal_data_t *dev) +{ + volatile uint64_t timeout = 1000000 * 32; + do { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) = IC_ABORT_BIT; + + if ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) & IC_ABORT_BIT) == 0) + return; + } while (timeout-- > 0); + + return; +} + +static void soc_i2c_enable_device(i2c_internal_data_t *dev, bool enable) +{ + volatile uint64_t timeout = 1000000 * 32; + do { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) = + enable ? IC_ENABLE_BIT : 0; + + if ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) == (enable ? IC_ENABLE_BIT : 0)) + return; + } while (timeout-- > 0); + + return; +} + +static void soc_end_data_transfer(i2c_internal_data_t *dev) +{ + uint32_t state = dev->state; + + if ((dev->mode == I2C_MASTER) && (dev->send_stop)) { + soc_i2c_enable_device(dev, false); + } + + dev->state = I2C_STATE_READY; + + if (I2C_CMD_RECV == state) { + if (NULL != dev->rx_cb) { + dev->cb_rx_data = dev->total_read_bytes; + dev->total_read_bytes = 0; + dev->rx_cb(dev->cb_rx_data); + } + } else if (I2C_CMD_SEND == state) { + if (NULL != dev->tx_cb) { + dev->tx_cb(dev->cb_tx_data); + } + } else if (I2C_CMD_SLAVE_SEND == state) { + dev->tx_len = dev->total_write_bytes = 0; + } else if (I2C_CMD_ERROR == state) { + if (NULL != dev->err_cb) { + dev->err_cb(dev->cb_err_data); + } + } +} + +static void soc_i2c_recv_data(i2c_internal_data_t *dev) +{ + uint32_t rx_valid = 0; + + rx_valid = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); + + for (; dev->total_read_bytes < dev->rx_len && rx_valid > 0; rx_valid--) { + dev->i2c_read_buff[dev->total_read_bytes++] = + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD); + } + + return; +} + +static void soc_i2c_xmit_data(i2c_internal_data_t *dev) +{ + uint32_t tx_limit, rx_limit; + + if (dev->mode == I2C_SLAVE) { + if (dev->total_write_bytes == dev->tx_len) { + if (NULL != dev->tx_cb) { + dev->tx_cb(dev->cb_tx_data); + } + } + } + + if (!dev->rx_tx_len) { + return; + } + + tx_limit = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TXFLR); + rx_limit = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); + + while (dev->total_write_bytes < dev->rx_tx_len && tx_limit > 0 && + rx_limit > 0) { + uint32_t cmd = 0; + if (dev->send_restart) { + cmd |= IC_RESTART_BIT; + dev->send_restart = false; + } + + if (((dev->total_write_bytes + 1) == dev->rx_tx_len) && + dev->send_stop) { + cmd |= IC_STOP_BIT; + } + + if (dev->tx_len > 0) { // something to transmit + cmd |= dev->i2c_write_buff[dev->total_write_bytes]; + } else { + cmd |= IC_CMD_BIT; + rx_limit--; + } + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = cmd; + tx_limit--; + dev->total_write_bytes++; + } +} + +/* SOC I2C interrupt handler */ +static void soc_i2c_isr(i2c_internal_data_t *dev) +{ + volatile uint32_t stat = 0; + stat = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); + + dev->cb_err_data = 0; + + if (stat & IC_INTR_RX_UNDER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_UNDER); + + if (stat & IC_INTR_RX_OVER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_OVER); + + if (stat & IC_INTR_TX_OVER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_TX_OVER); + + if (stat & IC_INTR_RD_REQ) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RD_REQ); + + if (stat & IC_INTR_TX_ABRT) { + dev->cb_err_data = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TX_ABRT_SOURCE); + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_TX_ABRT); + } + + if (stat & IC_INTR_RX_DONE) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_DONE); + + if (stat & IC_INTR_ACTIVITY) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_ACTIVITY); + + if (stat & IC_INTR_STOP_DET) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_STOP_DET); + + if (stat & IC_INTR_START_DET) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_START_DET); + + if (stat & IC_INTR_GEN_CALL) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_GEN_CALL); + + if (stat & (IC_INTR_TX_ABRT | IC_INTR_TX_OVER | IC_INTR_RX_OVER | + IC_INTR_RX_UNDER)) { + dev->state = I2C_CMD_ERROR; + dev->send_stop = true; + goto done; + } + + if (!dev->send_stop && dev->total_write_bytes == dev->rx_tx_len && + dev->total_read_bytes == dev->rx_len) { + int mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); + mask &= ~IC_INTR_TX_EMPTY; + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; + goto done; + } + + if (stat & IC_INTR_RX_FULL) { + dev->state = I2C_CMD_RECV; + soc_i2c_recv_data(dev); + } + + if (stat & IC_INTR_TX_EMPTY) { + soc_i2c_xmit_data(dev); + } + + if (stat & IC_INTR_RD_REQ) { + dev->state = I2C_CMD_SLAVE_SEND; + soc_i2c_xmit_data(dev); + } + + if (stat & IC_INTR_RX_DONE) { + goto done; + } + + if (stat & IC_INTR_STOP_DET) { + goto done; + } + + return; + +done: + soc_end_data_transfer(dev); +} + +DECLARE_INTERRUPT_HANDLER void isr_dev_0() +{ + soc_i2c_isr(&devices[0]); +} + +DECLARE_INTERRUPT_HANDLER void isr_dev_1() +{ + soc_i2c_isr(&devices[1]); +} + +static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev) +{ + volatile uint32_t ic_con = 0, ic_tar = 0; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + /* Set addressing mode - (initialisation = 7 bit) */ + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_MASTER_ADDR_MODE_BIT; + ic_tar = IC_TAR_10BITADDR_MASTER; + } else { + ic_con &= ~IC_MASTER_ADDR_MODE_BIT; + } + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + /* Set slave address */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = ic_tar | dev->slave_addr; + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + soc_i2c_enable_device(dev, true); + + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_RX_TX_INT_I2C; + + return; +} + +static DRIVER_API_RC soc_i2c_init(i2c_internal_data_t *dev) +{ + volatile uint32_t ic_con = 0; + DRIVER_API_RC rc = DRV_RC_OK; + uint32_t i = 0; + + dev->send_stop = true; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = IC_STOP_DET_IFADDRESSED; + + /* Set master or slave mode - (initialisation = slave) */ + if (I2C_MASTER == dev->mode) { + ic_con |= IC_SLAVE_DISABLE_BIT; /* SET TRUE */ + ic_con |= IC_MASTER_EN_BIT; + } else { + ic_con &= (~IC_SLAVE_DISABLE_BIT); /* SET TRUE */ + ic_con &= (~IC_MASTER_EN_BIT); + } + + /* Set restart - so far compile time option - (initialisation = OFF) */ + ic_con |= IC_RESTART_EN_BIT; + + /* Set addressing mode - (initialisation = 7 bit) */ + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_MASTER_ADDR_MODE_BIT; + ic_con |= IC_SLAVE_ADDR_MODE_BIT; + } + + /* Set speed */ + ic_con |= (dev->speed << 1); + + /* Set TX interrupt mode */ + ic_con |= IC_TX_INTR_MODE; + + /* Set the IC_CON register */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + /* Wait for register to set */ + while (MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) != ic_con) { + i++; + if (i >= STATUS_DELAY) { + rc = DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* END of setup IC_CON */ + + if (I2C_SLOW == + dev->speed) /* This is setter so prefering readability above speed */ + { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = I2C_STD_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = I2C_STD_LCNT; + } else if (I2C_FAST == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_HCNT) = I2C_FS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_LCNT) = I2C_FS_LCNT; + } else if (I2C_HS == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_HCNT) = I2C_HS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_LCNT) = I2C_HS_LCNT; + } else { + rc = DRV_RC_FAIL; + } + + /* Set RX fifo threshold level */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RX_TL) = dev->rx_watermark; + /* Set TX fifo threshold level */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TX_TL) = dev->tx_watermark; + + dev->tx_len = dev->total_write_bytes = 0; + dev->rx_len = dev->total_read_bytes = 0; + + if (dev->mode == I2C_SLAVE) { + /* Set slave address */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = dev->slave_addr; + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_DISABLE_ALL_I2C_INT; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + soc_i2c_enable_device(dev, true); + + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_ENABLE_INT_I2C_SLAVE; + + soc_i2c_enable_device(dev, true); + } + + return rc; +} + +DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config) +{ + i2c_internal_data_t *dev; + + /* set current base based on config */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + dev->ISR = &isr_dev_0; + dev->BASE = SOC_I2C_0_BASE; + dev->clk_gate_info.clk_gate_register = PERIPH_CLK_GATE_CTRL; + dev->clk_gate_info.bits_mask = I2C0_CLK_GATE_MASK; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + dev->ISR = &isr_dev_1; + dev->BASE = SOC_I2C_1_BASE; + dev->clk_gate_info.clk_gate_register = PERIPH_CLK_GATE_CTRL; + dev->clk_gate_info.bits_mask = I2C1_CLK_GATE_MASK; + } else { + return DRV_RC_FAIL; + } + + /* Copy passed in config data locally */ + dev->speed = config->speed; + dev->addr_mode = config->addressing_mode; + dev->mode = config->mode_type; + dev->slave_addr = config->slave_adr; + dev->rx_cb = config->cb_rx; + dev->cb_rx_data = config->cb_rx_data; + dev->tx_cb = config->cb_tx; + dev->cb_tx_data = config->cb_tx_data; + dev->err_cb = config->cb_err; + dev->cb_err_data = config->cb_err_data; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + if (controller_id == SOC_I2C_0) { + SET_INTERRUPT_HANDLER(SOC_I2C0_INTERRUPT, dev->ISR); + /* Unmask interrupts */ + SOC_UNMASK_INTERRUPTS(INT_I2C_0_MASK); + } else { + SET_INTERRUPT_HANDLER(SOC_I2C1_INTERRUPT, dev->ISR); + /* Unmask interrupts */ + SOC_UNMASK_INTERRUPTS(INT_I2C_1_MASK); + } + + if (I2C_SLAVE == dev->mode) { + /* Set reset values (moved from reset dev - was called only once) */ + dev->rx_watermark = 0; // TODO test different watermark levels + dev->tx_watermark = 0; + dev->fifo_depth = 1; + } else { + /* Set reset values (moved from reset dev - was called only once) */ + dev->rx_watermark = 0; // TODO test different watermark levels + dev->tx_watermark = 0; + dev->fifo_depth = 16; + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config) +{ + /* TODO implement */ + controller_id = controller_id; + config = config; + return DRV_RC_FAIL; +} + +DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) +{ + i2c_internal_data_t *dev = NULL; + DRIVER_API_RC rc = DRV_RC_OK; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + if (!dev->send_stop) { + soc_i2c_abort_transfer(dev); + } + + soc_i2c_enable_device(dev, false); + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + return rc; +} + +DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) +{ + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + set_clock_gate(&dev->clk_gate_info, CLK_GATE_ON); + + soc_i2c_init(dev); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) +{ + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + set_clock_gate(&dev->clk_gate_info, CLK_GATE_OFF); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_set_transfer_speed(SOC_I2C_CONTROLLER controller_id, + uint32_t speed) +{ + volatile uint32_t ic_con = 0; + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->speed = speed; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + ic_con |= (dev->speed << 1); + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + if (I2C_SLOW == + dev->speed) /* This is setter so prefering readability above speed */ + { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = I2C_STD_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = I2C_STD_LCNT; + } else if (I2C_FAST == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_HCNT) = I2C_FS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_LCNT) = I2C_FS_LCNT; + } else if (I2C_HS == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_HCNT) = I2C_HS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_LCNT) = I2C_HS_LCNT; + } else { + return DRV_RC_FAIL; + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode) +{ + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->addr_mode = mode; + + if (dev->mode == I2C_SLAVE) { + volatile uint32_t ic_con = 0; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_SLAVE_ADDR_MODE_BIT; + } else { + ic_con &= ~IC_SLAVE_ADDR_MODE_BIT; + } + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + soc_i2c_enable_device(dev, true); + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len) +{ + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->tx_len = data_write_len; + dev->rx_tx_len = data_write_len; + dev->i2c_write_buff = data_write; + dev->total_write_bytes = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_read, + uint32_t data_read_len) +{ + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->rx_len = data_read_len; + dev->rx_tx_len = data_read_len; + dev->i2c_read_buff = data_read; + dev->total_read_bytes = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop) +{ + return soc_i2c_master_transfer(controller_id, data, data_len, 0, 0, + slave_addr, no_stop); +} + +DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop) +{ + return soc_i2c_master_transfer(controller_id, 0, 0, data, data_len, + slave_addr, no_stop); +} + +DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len, + uint8_t *data_read, + uint32_t data_read_len, + uint32_t slave_addr, bool no_stop) +{ + bool need_init = true; + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + /* Check for activity */ + if (I2C_OK != soc_i2c_status(controller_id, !dev->send_stop)) { + return DRV_RC_FAIL; + } + + if ((data_read_len == 0) && (data_write_len == 0)) { + // Workaround: we know that we are doing I2C bus scan. + data_read_len = 1; + dev->send_restart = true; + } + + if (data_read_len > 0) { + dev->state = I2C_CMD_RECV; + } else { + dev->state = I2C_CMD_SEND; + } + dev->rx_len = data_read_len; + dev->tx_len = data_write_len; + dev->rx_tx_len = data_read_len + data_write_len; + dev->i2c_write_buff = data_write; + dev->i2c_read_buff = data_read; + dev->total_read_bytes = 0; + dev->total_write_bytes = 0; + + if (dev->slave_addr != slave_addr) { + dev->send_restart = true; + } + + dev->slave_addr = slave_addr; + + need_init = dev->send_stop || dev->send_restart; + + if (!no_stop) { + dev->send_stop = true; + } else { + dev->send_stop = false; + } + + if (need_init) { + soc_i2c_master_init_transfer(dev); + } else { + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_ENABLE_RX_TX_INT_I2C; + } + + return DRV_RC_OK; +} + +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id, + bool no_stop) +{ + uint32_t status = 0; + DRIVER_I2C_STATUS_CODE rc = I2C_OK; + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STATUS); + if (((!no_stop) && (status & IC_STATUS_ACTIVITY)) || + (status & IC_STATUS_RFNE) || !(status & IC_STATUS_TFE)) { + rc = I2C_BUSY; + } else { + uint32_t int_status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); + if (int_status & IC_INTR_TX_ABRT) { + rc = I2C_TX_ABORT; + } + if (int_status & IC_INTR_TX_OVER) { + rc = I2C_TX_OVER; + } + if (int_status & IC_INTR_RX_OVER) { + rc = I2C_RX_OVER; + } + if (int_status & IC_INTR_RX_UNDER) { + rc = I2C_RX_UNDER; + } + } + + return rc; +} diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.h b/system/libarc32_arduino101/drivers/intel_qrk_i2c.h new file mode 100644 index 00000000..8b55339f --- /dev/null +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QRK_SOC_I2C_H_ +#define QRK_SOC_I2C_H_ + +#include "common_i2c.h" +#include "data_type.h" +#include "platform.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup common_drivers Common Drivers + * Definition of the drivers APIs accessible from any processor. + * @ingroup drivers + */ + +/** + * @defgroup soc_i2c Atlaspeak SOC I2C + * Atlaspeak SOC Inter-Integrated Circuit drivers API. + * @ingroup common_drivers + * @{ + */ + +#define SOC_I2C_CONTROLLER int + +typedef enum { + SLAVE_WRITE = 0, /*!< SLAVE WRITE MODE */ + SLAVE_READ, /*!< SLAVE READ MODE */ +} SOC_I2C_SLAVE_MODE; + +/** + * Configure the specified I2C controller. + * + * Configuration parameters must be valid or an error is returned - see return values below. + * + * @param controller_id I2C controller identifier + * @param config Pointer to configuration structure + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_DEVICE_TYPE_NOT_SUPPORTED - if device type is not supported by this controller + * - DRV_RC_INVALID_CONFIG - if any configuration parameters are not valid + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_CONTROLLER_NOT_ACCESSIBLE - if controller is not accessible from this core + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t * config); + + +/** + * Retrieve configuration of the specified I2C controller + * + * @param controller_id I2C controller identifier + * @param config Pointer to configuration structure to store current setup + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t * config); + + +/** + * Place the I2C controller into a disabled and default state (as if hardware reset occurred). + * + * This function assumes that there is no pending transaction on the I2C interface in question. + * It is the responsibility of the calling application to do so. + * Upon success, the specified controller configuration is reset to default. + * + * @param controller_id I2C controller identifier + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id); + + +/** + * Enable the clock for the specified I2C controller. + * + * Upon success, the specified I2C interface is no longer clock gated in hardware, it is now + * capable of transmitting and receiving on the I2C bus, and generating interrupts. + * + * @param sba_dev Pointer to bus configuration data + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id); + + +/** + * Disable the clock for the specified I2C controller. + * + * This function assumes that there is no pending transaction on the I2C interface in question. + * It is the responsibility of the calling application to do so. + * Upon success, the specified I2C interface is clock gated in hardware, + * it is no longer capable of generating interrupts. + * + * @param sba_dev Pointer to bus configuration data + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id); + + +/** + * Send a block of data to the specified I2C slave. + * + * @param controller_id I2C controller identifier + * @param data Pointer to data to write + * @param data_len Length of data to write + * @param slave_addr I2C address of the slave to write data to + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop); + +/** + * Receive a block of data from the specified I2C slave. + * + * If set as a master, this will receive 'data_len' bytes transmitted from slave. + * If set as a slave, this will receive any data sent by a master addressed to the I2C address as + * configured in the "slave_adr" for this controller configuration, in which case 'data_len' + * indicates the amount of data received and 'data' holds the data. + * + * @param controller_id I2C controller identifier + * @param data Pointer where to store read data + * @param data_len Length of data to read + * @param slave_addr I2C address of the slave + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop); + +/** + * Send and receive a block of data to the specified I2C slave + * with repeated start + * + * @param controller_id I2C controller identifier + * @param data_write Pointer to data to write + * @param data_write_len Length of data to write + * @param data_read Pointer where to store read data + * @param data_read_len Length of data to read + * @param slave_addr I2C address of the slave + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, uint32_t data_write_len, + uint8_t *data_read, uint32_t data_read_len, + uint32_t slave_addr, bool no_stop); + +/** +* Function to determine controllers current state +* +* @param controller_id : I2C controller identifier +* +* @return +* - I2C_OK - controller ready +* - I2C_BUSY - controller busy +*/ +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id, bool stop); + +/** +* Function to set I2C slave device receive buffer +* +* @param controller_id : I2C controller_id identifier +* @param data_read : pointer to data to read +* @param data_read_len : length of data to read +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_read, + uint32_t data_read_len); + +/** +* Function to set I2C slave device transmit buffer +* +* @param controller_id : I2C controller_id identifier +* @param data_write : pointer to data to write +* @param data_write_len : length of data to write +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len); + +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param speed : I2C speed +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_speed(SOC_I2C_CONTROLLER controller_id, + uint32_t speed); +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param mode : address mode +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode); +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param mode : address mode +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/system/libarc32_arduino101/drivers/soc_i2c_priv.h b/system/libarc32_arduino101/drivers/soc_i2c_priv.h new file mode 100644 index 00000000..0e1973bf --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_i2c_priv.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_I2C_PRIV_H_ +#define SOC_I2C_PRIV_H_ + + +#define INT_I2C_0_MASK (0x448) +#define INT_I2C_1_MASK (0x44C) + +#define SCSS_BASE SCSS_REGISTER_BASE + +#define INT_I2C_MASK_RW (uint32_t)(0xb0800448) + +/* QRK interrupt values */ +#define QRK_I2C_INT_MASK (0x01010100) + +/* QRK interrupt values */ + +#define SOC_ENABLE_RX_TX_INT_I2C \ + (IC_INTR_RX_UNDER | IC_INTR_RX_OVER | IC_INTR_RX_FULL | IC_INTR_TX_OVER | \ + IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET) +#define SOC_ENABLE_TX_INT_I2C \ + (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET) +#define SOC_ENABLE_INT_I2C_SLAVE \ + (IC_INTR_TX_OVER | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | IC_INTR_RX_DONE | \ + IC_INTR_RX_FULL | IC_INTR_RX_OVER | IC_INTR_RX_UNDER | IC_INTR_STOP_DET) + +#define SOC_ENABLE_TX_INT_I2C_SLAVE (0x00000260) +#define SOC_ENABLE_RX_INT_I2C_SLAVE (0x00000204) +#define SOC_DISABLE_ALL_I2C_INT (0x00000000) + +/* IC_CON speed settings (bit 1:2) */ + +#define I2C_STD_SPEED 01 +#define I2C_FAST_SPEED 10 +#define I2C_HIGH_SPEED 11 + +/* IC_CON addressing settings (bit 4) */ + +#define I2C_7BIT_ADDR 0 +#define I2C_10BIT_ADDR 1 + +/* IC_CON Low count and high count default values */ +// TODO verify values for high and fast speed +#define I2C_STD_HCNT (CLOCK_SPEED * 4) +#define I2C_STD_LCNT (CLOCK_SPEED * 5) +#define I2C_FS_HCNT ((CLOCK_SPEED * 6) / 8) +#define I2C_FS_LCNT ((CLOCK_SPEED * 7) / 8) +#define I2C_HS_HCNT ((CLOCK_SPEED * 6) / 8) +#define I2C_HS_LCNT ((CLOCK_SPEED * 7) / 8) + +/* IC_DATA_CMD Data transfer mode settings (bit 8) */ +#define I2C_STATE_READY (0) +#define I2C_CMD_SEND (1 << 0) +#define I2C_CMD_RECV (1 << 1) +#define I2C_CMD_SLAVE_RECV I2C_CMD_RECV +#define I2C_CMD_SLAVE_SEND (1 << 2) +#define I2C_CMD_ERROR (1 << 3) + +/* Reset vectors for configuration registers */ +#define IC_CON_RST ((uint32_t)0x7e) +#define IC_TAR_RST ((uint32_t)0x55) + +/* FIFO size */ +#define FIFO_SIZE 16 + +/* APB I2C register offsets */ +#define IC_CON (0x00) +#define IC_TAR (0x04) +#define IC_SAR (0x08) +#define IC_HS_MADDR (0x0c) +#define IC_DATA_CMD (0x10) +#define IC_STD_SCL_HCNT (0x14) +#define IC_STD_SCL_LCNT (0x18) +#define IC_FS_SCL_HCNT (0x1c) +#define IC_FS_SCL_LCNT (0x20) +#define IC_HS_SCL_HCNT (0x24) +#define IC_HS_SCL_LCNT (0x28) +#define IC_INTR_STAT (0x2c) +#define IC_INTR_MASK (0x30) +#define IC_RAW_INTR_STAT (0x34) +#define IC_RX_TL (0x38) +#define IC_TX_TL (0x3c) +#define IC_CLR_INTR (0x40) +#define IC_CLR_RX_UNDER (0x44) +#define IC_CLR_RX_OVER (0x48) +#define IC_CLR_TX_OVER (0x4c) +#define IC_CLR_RD_REQ (0x50) +#define IC_CLR_TX_ABRT (0x54) +#define IC_CLR_RX_DONE (0x58) +#define IC_CLR_ACTIVITY (0x5c) +#define IC_CLR_STOP_DET (0x60) +#define IC_CLR_START_DET (0x64) +#define IC_CLR_GEN_CALL (0x68) +#define IC_ENABLE (0x6c) +#define IC_STATUS (0x70) +#define IC_TXFLR (0x74) +#define IC_RXFLR (0x78) +#define IC_SDA_HOLD (0x7c) +#define IC_TX_ABRT_SOURCE (0x80) +#define IC_SLV_DATA_NACK_ONLY (0x84) +#define IC_DMA_CR (0x88) +#define IC_DMA_TDLR (0x8c) +#define IC_DMA_RDLR (0x90) +#define IC_SDA_SETUP (0x94) +#define IC_ACK_GENERAL_CALL (0x98) +#define IC_ENABLE_STATUS (0x9c) +#define IC_FS_SPKLEN (0xa0) +#define IC_HS_SPKLEN (0xa4) +#define IC_CLR_RESTART_DET (0xa8) +#define IC_COMP_PARAM_1 (0xf4) +#define IC_COMP_VERSION (0xf8) +#define IC_COMP_TYPE (0xfc) + +#define RESTART_ALLOWED 0 // WARNING TODO Check whether this will be compile time or driver option + +/* Specific bits used to set certain regs */ +#define IC_RESTART_BIT (1 << 10) +#define IC_CMD_BIT (1 << 8) /* part of IC_DATA_CMD register, sets direction of current byte - set (1) = read, unset (0) = write */ +#define IC_STOP_BIT (1 << 9) /* part of IC_DATA_CMD, by setting this bit last byte of transfer is indicated */ +#define IC_TX_INTR_MODE (1 << 8) /* part of IC_CON registers - set TX interrupt mode*/ +#define IC_ENABLE_BIT (1 << 0) +#define IC_ABORT_BIT (1 << 1) +#define IC_SLAVE_DISABLE_BIT (1 << 6) +#define IC_STOP_DET_IFADDRESSED (1 << 7) +#define IC_MASTER_EN_BIT (1 << 0) +#define IC_RESTART_EN_BIT (1 << 5) +#define IC_MASTER_ADDR_MODE_BIT (1 << 4) +#define IC_SLAVE_ADDR_MODE_BIT (1 << 3) +#define IC_ACTIVITY (1 << 0) +#define IC_TAR_10BITADDR_MASTER (1 << 12) + +/* Out of convention */ +#define IC_SPEED_POS 2 + +#define ZERO_REG ((uint32_t)(0x00000000)) + +/* Clock gating */ +#define CLK_I2C_0_ENABLE (1 << 19) +#define CLK_I2C_1_ENABLE (1 << 20) +#define CLK_I2C_0_DISABLE (~CLK_I2C_0_ENABLE) +#define CLK_I2C_1_DISABLE (~CLK_I2C_1_ENABLE) + +#define STATUS_DELAY 1000 /* User configurable option - waits for controller status change (no interrupt available - occurs only when two transactions are initiated in short time) - normally shouldn't take more than 2-3 cycles, cycle is exited when set */ + +/* Interrupt handler statuses - bit masking for IC_RAW_INTR_STATUS register - passed by callbacks */ +#define IC_INTR_RX_UNDER (1 << 0) +#define IC_INTR_RX_OVER (1 << 1) /* RX fifo overflow */ +#define IC_INTR_RX_FULL (1 << 2) /* RX fifo full */ +#define IC_INTR_TX_OVER (1 << 3) /* TX fifo overflow */ +#define IC_INTR_TX_EMPTY (1 << 4) /* TX fifo empty */ +#define IC_INTR_RD_REQ (1 << 5) /* SLAVE - read request received */ +#define IC_INTR_TX_ABRT (1 << 6) /* TX aborted - TODO reason */ +#define IC_INTR_RX_DONE (1 << 7) /* SLAVE - read on master over */ +#define IC_INTR_ACTIVITY (1 << 8) /* Activity on I2C - automatically cleared by ISR */ +#define IC_INTR_STOP_DET (1 << 9) /* STOP condition on line */ +#define IC_INTR_START_DET (1 << 10) /* START condition on line */ +#define IC_INTR_GEN_CALL (1 << 11) /* General call issued - disabled */ +#define IC_INTR_RESTART_DET (1 << 12) /* SLAVE - restart condition - disabled */ +#define IC_INTR_MST_ON_HOLD (1 << 13) /* Master on hold - disabled */ + +#define IC_STATUS_ACTIVITY (1 << 0) +#define IC_STATUS_TFNF (1 << 1) +#define IC_STATUS_TFE (1 << 2) +#define IC_STATUS_RFNE (1 << 3) +#define IC_STATUS_RFF (1 << 4) +#define IC_STATUS_MST_ACTIVITY (1 << 5) +#define IC_STATUS_SLV_ACTIVITY (1 << 6) + +#endif diff --git a/system/libarc32_arduino101/drivers/spi_priv.h b/system/libarc32_arduino101/drivers/spi_priv.h index 9dd9e3fb..d46127d9 100644 --- a/system/libarc32_arduino101/drivers/spi_priv.h +++ b/system/libarc32_arduino101/drivers/spi_priv.h @@ -96,7 +96,7 @@ #define SPI_ENABLE_INT (SPI_ENABLE_TX_INT | SPI_ENABLE_RX_INT) #define SPI_RX_CLR_INTR (RXFIS) -#define SPI_ERR_CLR_INTR (RXOIS | RXUIS | TXOIS) +#define SPI_ERR_CLR_INTR (RXOIS |?RXUIS | TXOIS) #define SPI_TX_CLR_INTR (TXEIS) // DR @@ -155,6 +155,8 @@ typedef struct spi_info_struct uint32_t spi_err_mask; /* CREG Master clock gate bit location */ uint8_t creg_spi_clk_ctrl; + SPI_SLAVE_ENABLE slave; + struct clk_gate_info_s *clk_gate_info; } spi_info_t, *spi_info_pt; diff --git a/system/libarc32_arduino101/drivers/ss_spi.c b/system/libarc32_arduino101/drivers/ss_spi.c new file mode 100644 index 00000000..20689aba --- /dev/null +++ b/system/libarc32_arduino101/drivers/ss_spi.c @@ -0,0 +1,248 @@ +/******************************************************************************* + * + * Synopsys DesignWare Sensor and Control IP Subsystem IO Software Driver and + * documentation (hereinafter, "Software") is an Unsupported proprietary work + * of Synopsys, Inc. unless otherwise expressly agreed to in writing between + * Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + +/******************************************************************************* + * + * Modifications Copyright (c) 2015, Intel Corporation. All rights reserved. + * + ******************************************************************************/ + +#include + +#include "common_spi.h" +#include "eiaextensions.h" +#include "portable.h" +#include "soc_gpio.h" +#include "spi_priv.h" +#include "clk_system.h" + +#include "ss_spi.h" + +#define SPI_MAX_CNT (2) + +/** + * Clock speed into SPI peripheral + */ +#define FREQ_SPI_CLOCK_IN \ + (CLOCK_SPEED * 1000 * 1000) /* CONFIG_CLOCK_SPEED in MHz */ + +static spi_info_t ss_spi_master_devs[SPI_MAX_CNT] = { + {.instID = 0, + .reg_base = AR_IO_SPI_MST0_CTRL, + .creg_spi_clk_ctrl = CREG_CLK_CTRL_SPI0, + .clk_gate_info = + &(struct clk_gate_info_s){ + .clk_gate_register = SS_PERIPH_CLK_GATE_CTL, + .bits_mask = SS_SPI0_CLK_GATE_MASK, + }}, + {.instID = 1, + .reg_base = AR_IO_SPI_MST1_CTRL, + .creg_spi_clk_ctrl = CREG_CLK_CTRL_SPI1, + .clk_gate_info = + &(struct clk_gate_info_s){ + .clk_gate_register = SS_PERIPH_CLK_GATE_CTL, + .bits_mask = SS_SPI1_CLK_GATE_MASK, + }}, +}; + +void ss_spi_set_clock_divider(SPI_CONTROLLER controller_id, uint8_t clockDiv) +{ + uint32_t spien, timing; + spi_info_pt dev = &ss_spi_master_devs[controller_id]; + + spien = READ_ARC_REG(dev->reg_base + SPIEN); + /* disable controller */ + WRITE_ARC_REG(SPI_DISABLE, dev->reg_base + SPIEN); + + /* Set SPI Clock Divider */ + timing = READ_ARC_REG(dev->reg_base + TIMING); + timing &= SPI_SCKDEV_SET_MASK; + timing |= clockDiv; + WRITE_ARC_REG(timing, dev->reg_base + TIMING); + + /* re-enable controller */ + WRITE_ARC_REG(spien | SPI_ENABLE, dev->reg_base + SPIEN); +} + +void ss_spi_set_data_mode(SPI_CONTROLLER controller_id, uint8_t dataMode) +{ + uint32_t spien, ctrl; + spi_info_pt dev = &ss_spi_master_devs[controller_id]; + + spien = READ_ARC_REG(dev->reg_base + SPIEN); + /* disable controller */ + WRITE_ARC_REG(SPI_DISABLE, dev->reg_base + SPIEN); + + /* Set frame size, bus mode and transfer mode */ + ctrl = READ_ARC_REG(dev->reg_base + CTRL); + ctrl &= (SPI_SCPL_SET_MASK & SPI_SCPH_SET_MASK); + ctrl = (dataMode << 6); + WRITE_ARC_REG(ctrl, dev->reg_base + CTRL); + + /* re-enable controller */ + WRITE_ARC_REG(spien | SPI_ENABLE, dev->reg_base + SPIEN); +} + +void ss_spi_init(SPI_CONTROLLER controller_id, uint32_t speed, + SPI_BUS_MODE mode, SPI_DATA_FRAME_SIZE data_frame_size, + SPI_SLAVE_ENABLE slave) +{ + uint32_t reg = 0; + uint32_t cs = 0; + spi_info_pt dev = &ss_spi_master_devs[controller_id]; + + dev->slave = slave; + if (dev->slave == SPI_SE_1) { + cs = 0; + } else if (dev->slave == SPI_SE_2) { + cs = 1; + } else if (dev->slave == SPI_SE_3) { + cs = 2; + } else if (dev->slave == SPI_SE_4) { + cs = 3; + } + + /* Configure pin-mux settings on the Intel Curie module to + * enable SPI mode usage */ + if (controller_id == SPI_SENSING_0) { + SET_PIN_MODE(28, QRK_PMUX_SEL_MODEA); // SPI0_SS_MISO + SET_PIN_MODE(29, QRK_PMUX_SEL_MODEA); // SPI0_SS_MOSI + SET_PIN_MODE(30, QRK_PMUX_SEL_MODEA); // SPI0_SS_SCK + SET_PIN_MODE(31 + cs, QRK_PMUX_SEL_MODEA); // SPI0_SS_CS_B[0] + } else if (controller_id == SPI_SENSING_1) { + SET_PIN_MODE(35, QRK_PMUX_SEL_MODEA); // SPI1_SS_MISO + SET_PIN_MODE(36, QRK_PMUX_SEL_MODEA); // SPI1_SS_MOSI + SET_PIN_MODE(37, QRK_PMUX_SEL_MODEA); // SPI1_SS_SCK + SET_PIN_MODE(38 + cs, QRK_PMUX_SEL_MODEA); // SPI0_SS_CS_B[0] + } + + /* enable clock to peripheral */ + set_clock_gate(dev->clk_gate_info, CLK_GATE_ON); + SET_ARC_BIT(AR_IO_CREG_MST0_CTRL, dev->creg_spi_clk_ctrl); + + /* disable controller */ + WRITE_ARC_REG(SPI_DISABLE, dev->reg_base + SPIEN); + /* enable clock to controller to allow reg writes */ + WRITE_ARC_REG(SPI_CLK_ENABLED, dev->reg_base + CTRL); + + /* Set frame size, bus mode and transfer mode */ + reg = SPI_CLK_ENABLED | data_frame_size | (mode << 6) | (SPI_TX_RX << 8); + WRITE_ARC_REG(reg, dev->reg_base + CTRL); + WRITE_ARC_REG((7 << 16) | 0, dev->reg_base + FTLR); + + reg = READ_ARC_REG(dev->reg_base + TIMING); + reg &= SPI_SCKDEV_SET_MASK; + reg |= FREQ_SPI_CLOCK_IN / (speed * BAUD_DIVISOR); + WRITE_ARC_REG(reg, dev->reg_base + TIMING); + + /* Disable interrupts */ + WRITE_ARC_REG(SPI_DISABLE_INT, dev->reg_base + INTR_MASK); +} + +void ss_spi_disable(SPI_CONTROLLER controller_id) +{ + spi_info_pt dev = &ss_spi_master_devs[controller_id]; + /* gate SPI controller clock */ + WRITE_ARC_REG(0, dev->reg_base + CTRL); +} + +static inline void spi_transmit(spi_info_pt dev, uint8_t *buf, size_t count, + boolean_t waitCompletion) +{ + while (count--) { + if (READ_ARC_REG(dev->reg_base + SR) & SPI_STATUS_TFNF) { + WRITE_ARC_REG(SPI_PUSH_DATA | *buf++, dev->reg_base + DR); + } + } + + /* Wait for transfer to complete */ + if (waitCompletion) + while (READ_ARC_REG(dev->reg_base + SR) & SPI_STATUS_BUSY) + ; +} + +static inline void spi_receive(spi_info_pt dev, uint8_t *buf, size_t count) +{ + while (count) { + if (READ_ARC_REG(dev->reg_base + RXFLR) > 0) { + WRITE_ARC_REG(SPI_POP_DATA, dev->reg_base + DR); + *buf++ = READ_ARC_REG(dev->reg_base + DR); + count--; + } + READ_ARC_REG(dev->reg_base + + RXFLR); /* Extra read of RXFLR, apparently necessary */ + } +} + +/* Polling-based SPI transfer to allow use within an ISR */ +int ss_spi_xfer(SPI_CONTROLLER controller_id, uint8_t *buf, unsigned tx_cnt, + unsigned rx_cnt) +{ + uint32_t spien = 0; + uint32_t ctrl = 0; + spi_info_pt dev = &ss_spi_master_devs[controller_id]; + + spien = READ_ARC_REG(dev->reg_base + SPIEN); + spien &= SPI_ENB_SET_MASK; + spien &= SPI_SER_SET_MASK; + spien |= (dev->slave << 4); + WRITE_ARC_REG(spien, dev->reg_base + SPIEN); + + ctrl = READ_ARC_REG(dev->reg_base + CTRL) & SPI_NDF_SET_MASK & + SPI_TMOD_SET_MASK; + ctrl |= (rx_cnt - 1) << 16; + if (tx_cnt == 0) { + ctrl |= (SPI_RX_ONLY << 8); + } else if (rx_cnt == 0) { + ctrl |= (SPI_TX_ONLY << 8); + } else { + ctrl |= (SPI_EPROM_RD << 8); + } + WRITE_ARC_REG(ctrl, dev->reg_base + CTRL); + + // Assert the slave-select and start the SPI transfer + WRITE_ARC_REG(spien | SPI_ENABLE, dev->reg_base + SPIEN); + + if (tx_cnt) + spi_transmit(dev, buf, tx_cnt, + !(rx_cnt)); // No wait for TX-RX transfers + else + WRITE_ARC_REG(SPI_PUSH_DATA | 0x56, + dev->reg_base + DR); // start rx-only transfert + + if (rx_cnt) + spi_receive(dev, buf, rx_cnt); + + // De-assert the slave-select and end the SPI transfer + WRITE_ARC_REG(0, dev->reg_base + SPIEN); + + return 0; +} diff --git a/libraries/CurieIMU/src/internal/ss_spi.h b/system/libarc32_arduino101/drivers/ss_spi.h similarity index 55% rename from libraries/CurieIMU/src/internal/ss_spi.h rename to system/libarc32_arduino101/drivers/ss_spi.h index f41d8f92..33c90c69 100644 --- a/libraries/CurieIMU/src/internal/ss_spi.h +++ b/system/libarc32_arduino101/drivers/ss_spi.h @@ -24,9 +24,24 @@ extern "C" { #endif -void ss_spi_init(); -void ss_spi_disable(); -int ss_spi_xfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt); +#include "common_spi.h" + +/** + * List of all controllers + */ +typedef enum { + SPI_SENSING_0, /* Sensing SPI controller 0, accessible by Sensor Subsystem Core only */ + SPI_SENSING_1 /* Sensing SPI controller 1, accessible by Sensor Subsystem Core only */ +} SPI_CONTROLLER; + +void ss_spi_init(SPI_CONTROLLER controller_id, uint32_t speed, + SPI_BUS_MODE mode, SPI_DATA_FRAME_SIZE data_frame_size, + SPI_SLAVE_ENABLE slave); +void ss_spi_disable(SPI_CONTROLLER controller_id); +int ss_spi_xfer(SPI_CONTROLLER controller_id, uint8_t *buf, unsigned tx_cnt, + unsigned rx_cnt); +void ss_spi_set_data_mode(SPI_CONTROLLER controller_id, uint8_t dataMode); +void ss_spi_set_clock_divider(SPI_CONTROLLER controller_id, uint8_t clockDiv); #ifdef __cplusplus } diff --git a/system/libarc32_arduino101/framework/include/platform.h b/system/libarc32_arduino101/framework/include/platform.h index 86b70ae9..0bd3830b 100644 --- a/system/libarc32_arduino101/framework/include/platform.h +++ b/system/libarc32_arduino101/framework/include/platform.h @@ -145,6 +145,7 @@ unsigned int get_timestamp(void); typedef enum { SOC_I2C_0 = 0, /*!< General Purpose I2C controller 0, accessible by both processing entities */ SOC_I2C_1, /*!< General Purpose I2C controller 1, accessible by both processing entities */ + NUM_SOC_I2C /*!< Number of SOC I2C connections */ } SOC_I2C_CONTROLLER_PF; /* SPI */ diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a deleted file mode 100644 index 8b179a8385f95cc3be74936955f88b4eb12a9572..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 496120 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%0Dgy82r0wAOXa9j8H3JY~s>tZ8h*`6;4I@7&Zc zj@4Gy)ZzS)Sbalf!?JqGQ%KQK4VgjX%>6JBO4zwhreIESV?aEFYY*602-z;CTtP z)i@3U=Q5dtt>mOJ7K0o%)79PGij6d7V@@rokl_02IyoFij)G$9Y(h~YX1h;UM)ZyM$AqIoBw4W>W4MQxVU;+I zAw9q0PV4E7J*^#Ri1?sxh?_`D+gMc_B}d)h5GiRE z)-+>C+19wa+pVhe=5uVt<5)tuLMs_+ok9%K5!BZ&tUfMmrQq~8M-?7H6cWISGPkm! zQo0Hb>SX6*d&FRDRY#W{gNnk&pgai1ny|ZFYZ4x$rdWGNb4xf0Tk5D8RX9q{Z7I9i zt*}_U?hQ>kp465)78Zl7vd5@FpW<{(%{}e1hq64VRwwC`o0Rmw?^`!SO`R;u%QFmM826Uh3D%Le^ zLe*l;lR6Y=jmo@kT}vCM%g)`l2WQ+>I+NL|S_m~qkolN2AK_~0-tU9Aw#>RVT7pyN$t~SYNXrN&4VPIf6 zw^`|yeotDagaKPsWx^SVa^Rt(7)~P$DHe=#p;ag-vF(-y7@bW*Pu}+Z5 zYUI&wfmP!}70suFw5)6CYDJ5RGPLbnIQ4{aa&PUzBjes2EVf`MgU2VFfHOE|kpu*420Cm5+x79GT-Dl!gBf_{Z!22*-u)epKc$Tl4oCQ`PB#pl2I_#*$XkyuW%FpEV^J(>a4N z6dcFLXty@Bw7Ev-xu2l|3XNxBdW?Ie#lxL1KYBJtD4IKr;-e%AYD;dF4hBxW`~QTI z5!7WZ{mbcAk08qSZcM0RNFRR2)d8ax7_E-9Gg=?=?I7*s*)BnLb) z?|950l5da)7@Q>xwIIhDEI!JyJwy<2$FD^p$qJ*b9G5s z5@z#~a7ZoHCLl?0yvIZ)4s_V1HAmuPO%iFALFP-6g$J*g$pf7xE}2b3PhwJ*_;4>- z62V()l0aKglLaMKgeMA`b>ySt zx&({qe-HAkepn?E$h!mBmG|5MB2S^b^^cICYb&xIz6T&+$|YaAOi z&XI@Z%7MJU0K4*dj!V==Qa*bB;9&YI9C>*fMm>i>m@985$#7 zdnJAa_}TnU56OE8^4z*=WlRalyVB9Gza#Hxl{XnQx;#7pB?iis^1$M?gwmY_zFop$ zE;ij2p>%ISx(mQki67Pl1o_w&lJ^qiMG&V+2k~j4L^3Dj! zd&-f=#V#(Lwv7|fgE-S>MUP*DBZbRv7-c* zv@%_O_+`_r4#^vIDEd|_40kK9A|&sYYp^yAft1H~#>zV`B=6^tcTW;|4Iz1Zz8JUj z3`bsDNZ!>@{tPCj&g!>1B=4DPVQ1Bk{gTyhqsrshfv#XC`o=7JK|br_2bQ@=72sLKkCPR7}Y2k(*b%nH{y(HC!&?dFxR>CPya08 zbT=vJ#}QZDrJAiS1462_(192HP6Y)yRd-vm9H}y5us(*f$B(;Iv)5ceNR^&B@PeN` zYuu$u&*=Kuv&CJi$DS$fc=oUBQoT{G7xGy`ahGcLS_lZKW>K-@XUiCOsb&FeKuDF- zAOkPtvt^09RB0JpKOQ2-rOFc=C!{9y^t2zJptwtwk(ukapL`lxDo%{ySch&Oeg&wF zu12hvl?+rzKgUSc(T`?4aP)J$ZXNwS)`L6!=Y{-Nh5X-Ce-!ruj2iA&Ki>@sQ2#hS zri6xhWM{ge^kPU$hjzh9xY#h`gxy*vn?*bo^3x=zX>1Vy^#>V$on9{ zKg!G1HX$nUM|;B){A0aC)jwRq$9oGB!Y6nu68sarjR}7AoSgfx(;D$_H{&xR;r}Bh zo>)AM)1sUm<39ur{117ZECnw=9Y{QGcv_PGCWJUJuNVK1WiV%Db#y1H9GWvbWvQVl zDN7E|L&fO{lTViH&NwAnGR@{XUCe-Qo3!wnlOeJ(K1 z0b7JS+d1Mhac7%m`41%LKy+rw%HRAkIUxWLiQR{nwV=%!l?ek*gj6W8UT{#K?-KTzBQrTb~o znQdD}9Qs?`J}vqEAv3~C2gm%{b2HiZS~}~TJ!6RFV(A-+Q4i^E#?R7kA zCLdLN6w-ZG@f_s$WyRlsJsF?;BcbzO6yF1VvfwA3XYLJDd_VFlXVQVrM_%TrfLoC6 zQOfgqRG6a`{{V9z%N73(OFI?r&HGr>WxfPLiLI^Ye^ne$1E%l%D%tN1Y3SG)&u?pFLf^nXzC zuc7BY#kaubPb$uV%x4u(f^IJ=9soJ7C}tb>YsG&D{Vl~$!47{`{2Fiy%AWdjPw!mC z2jf0e@gCTJjAHJrIz{o{k>4W~$55sV6@M9JcdTOW2;8LjUC8fH{5I+#=c1VIK=53t zcpBvFQv5K=Znz;doP`1?X1Im;Wk8R4uql=FAUmovM8??f5NIo-flK%Y6vvki7w zs+jpbQ8Du?=Wc_a?E}xjrOa=ljLua|+GUC_hD_EE^7ydBHx-|YXYf0g2j#L)aSQVG zvSQljFN(Lo4jh9}4$n`|QoIj383HpTBj{{4#2NBw+O@t=VIu6RGnr2u(mS{K4@ z|A)PIfv>7K*Z^PsYpbnRYt>f8yS;mDwY8_e=b3qD?b$mUv42m``J8k9^U2!l zyWaKAJMUc9ZPsMX5MkZ}l?k)_rwTVCU)92o!nad|=}(LBFCgC}{AZNO<-&I(&AWuZ z3H|R1PlFFX60SyF{6csU{5&Mg$tM0F+y?$sm}SWOJNo}KaE9=cC=<>bO*z{z=N%`r z4VMYC4VMew34i7Y^Gn4Gg_%~f@Pp7fQ=@Z-X4!@m$_8-7)oWvk}VMqK9cFCxDJ%c&CmM#%0^!TybCadtZggOC zy>M^vR!fKTWYZsh{Cl@>4a(#$;U2KRS9k!*@B!f!DBB+iccR>WDm)85JS+S=wE15N zKa9Aq2v;G$ZwhmM^4|*YKw5tmo&^3xxC?gvF5DOFVxiA@@S%tB@3B8k_)c&i;dJQq z7k&uo4iVmnx+@Sqgt|CdxEI>SXyFTyukpegAfF;U5am-Lyb*1qO87n4uMu7hoq597 zBJZaNzm5DZ5pIT`tz^VwI9KE&k?v-)bZ>7H`F{9tmB{Bn|9X*k!v1X{-vs%$g?S$P zuITU{|A5Hf1wStG{V3;WMBW?6=`YFfrx-e~3eN`rQ}_(=8Nh^=*-#2l)ZvyTOl>v7e7}e-ie|X`R7;%aGX=l_nsj#>@Y99N2i=~GUp06f`^e|pXFRF?13A} zi2DN4T1iH`W>_b3`mluzn`>a_5|KAT?`n}>3;EYYP9JuQ{6WaSBh2SMJ}=QeeK;iS zfqzFHit9JsH07J;ZHf91{%R7CC)>gbbhGhMfZ< zr*A(Mc@pybvM^_%dW{S_EFVs2LiWI!WTZ74$2iYfray$VjUab|#9P*Q^SW zFNJ)T$bSTzbt1n4@{>eP-*~>Gokt<(b2#}m@M<#h#O{t8g;^%w7cK|CNQR$RqmJJo zqn$E*Aaa(;-^s8ULR#!7p+4`sQpk{x0QV9(ue1F{J`eK2BB!5)B0nEIUienZL&^u#roacdDbgA5&(;Xsk|{?rpW(>+?`H$Z-@@RQ(jGUBlwmkW;sUnG1S_+B#X z&p|ox-q-XuK0}5NAHvQrMTf@%?++;NgZBBh$m!erB0nDTPee}N_}ZKLDWQ z{W)3W7eao9@O|JmGVHURTr2E>?;*p72hdKwOUAU&SM_O~pNGlI^>O_7nbWRgF?+2HNoaL}m zWGwh|ej@CFUn9fkCsCKbBTL`)XCi0$ zP)46$hMiCX>D{wU->7k&-=JQ-=RS$;0e_M8bB{W%Hc zpF?J+6T;CVr$6J!@aIGDu_EWOJVWGta7>*ja{4e|t!XoE=Vwv7@!Twy~DX1d`^X!8|Pw_CU(VTqd<(4{=v8GRkVMZ~}SGg7!2;YTu zk;SFL_hUWDV#cS$y1%**Hki+PVuecErdc$qNmpK0-GVcOp$jFoe-@F=V= zv-nD3=Jy7RZxN=ydn~?3nD!qPuEqK>;RdXqwD@UZ`v1JeFA9GL>vx5*a(*v780(KM z{#2N0{Zp8E54e%?*27?n*@tfGbcDsDgqh!CES@M#|I3A$?sVaY!6#bG z@js@1`D|&PJ(mdM65zC0tlkZw&3cgYnbYWBD4YTLHjBR|OgmRwe7!L3@OjldtEzWN zu#ZDhJ%5_#)5oZT zmoQE-`aKlvkOzo72du_kLryLbIopGJhYLBG?@nlQ2Y9^2#|krDJ|~-W)jKTcGr#H` zmauvk45mJxpN)QpFpv9lEZ!hY-!@yU-eJKGeY;%bRpv^Fralj zi21B;^alvD9p+kGVCnN2-sm4|=}fa&y`Pe_)cYynxt1M1|I-f7yJ}o6nC+I&^X7T~ z9AWx@zQvn`J;?c-Z}fKx)Bjs7zQfYz^S{x5#M1ep#ZL$`-Je;k-b3M@g6XpF!1Nou zCrtm@7hw7d{w{np9W6r>GJxi z-hY8NgW2C<{P~VB?X$mw@>9V-7G45=#$x_o2X$H@XTOH&_fYTAdg}K7zQ|dp{J#y; zkHP*9qn{$o_LFIGUtz}0vDg##AZK3*?Xd2~39~)0@5A(suy2~ok;b(a^ZzO+FNd6c zB1ZoVVb;r;7OxiOIb@y18-;0yeJIAxHNv#RnI9=9-y%#qdn~?3xEyl!xfnZ-3Df^4 zEq>b4XTJ>fS$A&=4+H&P9#W5MkAG5tah3G?{cZ}CCl8zEP~M>{<4O%>*Ok9}>X|E)oo?f(>u!@|cwuHF&j*^Xhg z$a(y(vzYJ0Xp?Q}B8x8(rXBX#nRIUvrky<&-y=+azGLxsg=vTVeYC?mdRjOi{Jh04 z3iEh>&EhwOr$EmBKGO%N-a+@)=l_3*oIbd?r=SkchwKM5`u&9IKj)jLoSY}jbJqxq zM+wso`wfkq3Sq`Q!QyJ+BFN`iyik~S*w1L}vICg<@#=SzAX_4SGkL&LU^SEYzsNY{I zOgm3otlrT>=t0hYQltN_Fn#!w#UEO6KeL!)xlBJQ`&h~JN4tcVarL)6g^`2e) zVV|t=|1M$r|1FC--jO;UG%Uuin2y zpZQ9{{TJor6k+PK-`41RmdIfQ+|rmy%f!YrSESnT4yk2)UY>?1b%{e)Q;m}ODP$$6GO`;LwN z1WV_5iz|egF30RrpIj~Mf!Xg&IqRiKnDxSbWYf=lmN4UPu=oOD4|4V|8~y8q>GMq% z-zH2ucUk;RVcKEewCR^VC`^CY*KGQte6J$jr(5~r|L{sql_dGK0y%-9ynEsPeGOj%g6R?=) z-*PgJPlj1o%=1?*8GbV?z+&zv7m=Ab!g4I;{->RcYca!GEap16k<5mQa4{Bhe%?W5 z1`)2qVvhHl$=Ucp*n`Eix4mR`njt)h#gsF*O*!CETk%1xLu3{h0-C>K4{N$^%7<=| z*+<7DO*7Llc1nuNz;y`0RG3_>dwGWFZZ zEEt3?EMyPswPZF_gmqZVwQ?g_>T#2>hxNr|oO>BA#X|P5-a%$zBV2`r%yZy%WSkQi zc3~lVSl>*RdfzSVVZDcpV}#)zEMyPs9tmJP+cQiiOB<*q%W-itIiz*&C(Ci6#_&s> z2H2k__1KS`s`ZP>a$HoBrH(EnOTDOmLaB?rluP-mzCI~)HJ)6``D5xx*@l8(DbImq zDZ>)7lpFsy!<5y0vXl@1f5wza$+)qe9Y&XpA3b4W*)d~|@x0NaOUI5KKL!C@S~{+* z%=5;UmQ5U|A}mTduX6Sb*L8J<@#{K2#1aYZXef#BxlD-)(dI`vAMD3$_0H`FKF|5_ z13N2rOf8(zUS4xvsFG5zJg=hMO9=gNDvq-(N^U97&US*I?+H~NDCc&0!PI`itbt{E zUsl$TQWv#($NocWKiID=GH!nrH~VF3KD(bDaX;himUK(JS>7!NQVKTiSoC3NhO_zm zp;Bl0Olo{S(D~Np&8dCe%%Ve+7Jc3)us8UJ;H3kWByFbU0a-oQYESm(;t zFEj0p6_J{?>$P@$>4p+7luO+qSvxD1&nz!U$YzY2D{@ypwfEk=IoZKrN`85JQTrax zNmwy#BTr+_vCAecq86=2N_NpD`Dbpp>%$MC+m`nQKFpet&^y7^?XdK`_Hz1>o3*im zw)5Y>YmH2_^P>_nLq|E8xmz;#We;+){lovStO%2~-)v&44-3Q{?&-+iY zA31jN^7M#6P#(3ZU6N6_IagCKU`UU**O2M z@)?cmBwGl6UH+;cf*n}bPC_2@8gSKxK9HcU{Q-Ro5D2L)tyX-JQVXd#>SuHdCG35M z74=hgE+zUtArMkKg26<7Dqe(2EpRMLM`7^!9g!G`!GNpGCk4|>IDkOkZ>V4P^WsTH z{jOKP>(np%g3+s`emRy9cUtOq*Lms|7WXnmIk1$>J&B`;cy2&Cl73<_QRgYCW*J!B zvn16j4?`i@oU1kiiLzOzHWP3OS1~h^PI(A1Q(K*+(>ad8No{Fzk`_}*-x?(~l9QAZ zNzLR?DnF)?w2Yjh15PYvD3vt0x7}S5T)_wB$!IS7tjmR)3DLY z-*qOoGPq0q(=zS~PvOg7RRh-*s@3&+^>w}4saL!7>IS{KQLk>&tDE)e7QMPvuWr+; z-FkJqUfrQrFY47xdiAni{aUYnqgSu!)vJ2-nqD2!tJn4F4ZV6(uinzDxAp2Bz1lWH z<>(TT>W>($rv>N36BF~aGc5jt=;%0k_*h8|-bX#8Qjj|XR>_;ihBg?{i8Xsg-? z?PvKqS?WEy-W?2m_-B9jM{2iL{g{Rm)FZGH3Jr4m;h78&Z(XxfYnM<)_lO9L=ZEHxDNG-dNqH>ti*!^>YYP zJDQy2m8vvS&+2fJR}o#ER8Ddi|94WGSxppP^Acj}Lm>GqmbpGIlh-mSeJm!QO-|Ku z&tWm@gD!a;|3xcH%h&VOZZ=$FEvE!oJt;vJzw$6O`N9YNBj(ehZV)M_}?r zbSp(iPD8yi5s`^g81J&u=Wu^WPGo z_&D8?G@sCE4opqXcKM%ds&yy#*GGgpa*_vFM?~^Kbxi5!%j6ujC!~f$Imv@ux}jY1 zQVQ=kE~Si!xRf%IEnBzpl%v^JwHql#OVB0;>BvPXV|rbKC(HI7hHxRoQuybDv`KD+8wt{ow%{jqry(~e!K*C zbKTm64ImUBv~nQOr_*=A1lQpFee)jOL;#))xid<4zAF<5;ly~>gl)#;ArH~)%j62gQe`r*TbbOUcO`7V(?64C{_VW| z0Q-BLi+V~4@=U1nc8y8OLkxGulE1U^Kxh`8_ zU8EJ}9JUqS679x|z8kkhyK!r@8@ENfaeFs6eiqM-L5FqYo@h7L<0XgA?>*6OsB3DZ zG`<<_)qT;Md!wEFb~h(Gk&G^@hDccrKCF`u87G&(19unyb5c9`P_&Z|8#fAgtLlEw zY-;64`1BFU!uO;1KI;42;<)=wg8H0#fGIL~{NaIm3L*nEhCCKZa zZhFrcv$W&x`kkMTXQK1*tZ_}};}>RA=i|BP&F6i`Rl|ItTVWsaeYFbPi{q+x@)hGG zlW}+PUo3UHuS7ffYP1`#QISC_AL2DIviW+nlW*QB${tl%pc^6ZTLdmbxxRl&g-7;P zN(EP@{HTL`H^jYo%as!3bzNuTqv%XD;vInY>!avQsD~crPFi8Z2Ynf^;fq|N|-v8IeeZ%^}~|wuYOcXqy%5au3o%#(Kc4|a>N@N zWuw2kIH^57u4F7Wzy7MslrXIyt&F0O&|lH5Ahf};kRI*0nQlRPpPqsAf$8)5Wx5&t zaA$cG{#AZb&trR5K_igw^z3;Y_Tw&75NC&~r9{0KLmE`_vYFl29o}C%fR7k4!2x|>bTVEv z4(y|oQdV-L#1IX~b+LPVf1NTTXS%(U%CoPX)}P4@PV{|BKuHfN^K;8hZ|emv>SMIZ zaqhMYTqhy>@@aU3mxmorrhE0Y{_Nu%ida%VjFqoq}{qWy7flEbru<!qTBaydv?l8ON=dnmR(QE;1IPowdruD7fl-jB3j& z+~_P=I+18rU5AY{I%BTm>lg)Bjet;F)Q!}&wIibImxq;ktEP-1J||q+|PBAa~=j^8Bh4~y?OECPPaIa>j4wFGJijvdax$ZlkM2`k{G$Uiko$;zNr6~u6~a|8nRRM0k_tDrwlpg>q=*S&T2?K? zz8?5*oX&99+3n5LMCS>*Pt?&A80mJMHX(mxYf0d2FOck=+=<~eXlb%{vU}o+V-pfA z$&-$|+erwzNhc&#&mJ-=H+M?O(1}A^2j`twQk0jwtfXXc-jtFdxw*MRN){ehGUe3s zr(mE`#NcO+drsh-;$g}}anhDKMWcpZjL1`_oD!pXo$H>E8vC6S}#1T|y*>t5>%)jUF=rv&y%3w6sOf0N&70AFisNUR5!*p{k}j zjH$+FggNgQ)8^GLbU6PuW=&T!@W`y{t8fH|JKGyolVhtz`-G9sHI3np&UUA>v9T#Es;gJE zbUE!|W~IAtQ>RZyCMsr!>*rU5IZ1do@9Qh8sWM%;to*7u(P5KSlOLHm&8N+-49`R+ z>%-cB+Nm9Y=dEq4mU-%D^{UR6WviN-JdT2E4>vV;HadQ0=T)CrU2{^k!(8a&Me-0n z!bD5zxa(TnwHgPLp3S^lHtMFchN>eKQLnN)vwEIap{E}AMy*scl~>LIwYGG1wKk7x zUe(mHconu+wTJ?`Z47Z0v1}Vv-%z35g_6*Zpm)I#>%*A#8u$ zYyYIWDzsTPYo5fUMX|UeZH{%=(bA5@yGM`P^wG*97OdEv9gX4kwvMjw;Tr1n%KD1B zs@jH{x;V!V4XL(|vS{zrd1Ur@)L7}QYU^rQiZgZ-b;Ep<&>n7Ij0<8XE)S^Nv%6;^ zas- z&Ow!ayoy;v2YR&&z@S}5IF-iRL!ZZnTN)1oj;p8yZmO!NoYAH8g3I7<6w|ujt7RrTbb^5qS_47)kPO>U#d^9jZ1Kb zaGKX57wX6evzASzH!gA7n>*0>yA=*E2oFnfbEpEyxv+-I;eZ$l`v_5la zp_q78RoAhl>JALW#_Nt0cYNp2fU9Q2oO{#(p{`hnx~$ngi2QOgUj4fs5xUo2UF95{ zF(Uc3+Eti`;ndkUm*61e(JWcUxiGx6b@4Ku2s=9$FKf06SY;B2sk$_4{cu+sPNVvP z0yjr%ls3z>ZE1K(m%iPIGyu+-hr5)HmL;pZn!{@rx30F$>ti05HCzn4=cWEj-9M=+ zU{jA*`_`pDJg2I@zN&hrIt}xHil?tm`Q4i$T8+A1IsR!$ournwb*x;B3+Zwkqw2=S z9KtB-@Ep`cU7Vv|B_Rz8b|XclW_ncjdVYa*Iy~{Hvvs$I8SkVUb#tj^S`5b;>}Drk zZdDmYJd;Tj^>G}ho}v#iaiV!uV_Q?R-z2)Fd)Uht;#&u#DrlaynsIedEyXIb$VEwA z*?Cp(mQLJOWEH$Vqwy5k+|kv7c4!)LyJ@bgm*Pe&D%EanT3uO9foY4Y;j}&xw=G?Y z!@yCE-{e8J8NWI4hQ&nJcl7F-ZO$LKTrcZd?m%k-T5XuOWGd_CfaL{p>=^8dwjn2b zXXWCx`iie^m1C6TSXR#v-AfO5fcjDyvAitKA>FOiW6wh!)jLdGlgCi8$&pcAO)}jWe^N zVv<*gXPCB??J!!Ro@TtN`l+7kE%LhB+FIdc%PNokHDgLgmlcm5GeSQl;rlS1XRpL_ z3)Wp7dcE9G7w$5gV&!`A5@e~kqq%i)F{QdGfx~EZJ8i@-hj<6rVJ!Oh zV9%l?qb2AgY(tY!dlxTR($TyoYIkc}W7IZ|4BSMSmZPJ^5w*6gLNa?Y(J83H;q*9kj9qv~(i;t(*mM^t%lgN3q!(e+ zF!x+_qNBd!P%Lup!`NUoM#8ptDP$fN6O4^H5E$mZ-@qO}0YG~!17mM3*tT~Mw%@~I zg0X=v+9-P;!ye<(9?QYlyBTcThaLt^~v31hasro-4vf|Bju z=a#(;%iic1dz)adNxPtajg6uhds(RP$`F@5UH=yDfY4)7U!@WADeX=NacjkDHIg z*gIt9m;Y;L?EN9e9>1aM(SQV#-*;o|eQMdufv&N46v`i}e&9Dd)7&@4=hQ`>NRfBJ_qoL5AhsD?{i?R0*hB%f(W`eQD z|K2preV^e3`xb^(nqc-#i%IvX#rWR8q&pPKCS48(HgRa<6`Wu<5+s;?oOhCOOxTU9 zz#eQc9|c&9y%jO`PAk;kr!n!2JvB$H5n?@ib)=kmjyLxBjcpT$>QBQS|LxHPv+wK} z|2D1B-=v{`Bd{2I+r(a}7i+B@-5 z%ie^2%OLgyqEh6xUDMn)S8r_wBducW@yZbi0d>W+x2*z(IH11hWbfyhGZF&oD{1yN z&s>oZP-jScTRx^EqJaMQNM9k~za-b9faCf52m$?H0=_KZ@Cb>7fNJ6PHd|;U1XK&N zw~vl&fCBj1lzb*h{XbuClrQVu1lIfUW&>+(*TrnN$8291vwdaE_U*FGb5?KE-+tMC zM{S3kS7e(jruWB~?T=%&^%otqkouhWnqdc)-net%_0t6IpBl40H)gw8wmsU9MfS#fzKiUQ^l7OY(OnEm$S1joUi`Z->}jsWDkE1j&z?q~XF4NS_Vcw4SH?bWaee)h$zp#CnHOt>Td^2^ z#Nr>5hv5g|7g$VMhsbi;Q|a=eih#?ppYAlW z-;y6B%dN%7mi$vP{*{q| z_vyxtnlpw4iNJd*BUf|4@J0?H2}_WLhd@{O&A!)RkGsj=fFJzqAGro)!RxyD-d`@6 zg^j@Kr_MDnGFJF4q{-u*@=>^DnkxJ-ZunHaK>h-B@Cc)H8ju#-DE0Y$>9FwEP?xR3 zi(&sv;rqZFgue%!&B8O`KkpA{=X}Vo6aEI|w+U~-dav+rQ1=fBbN=7Qg)^Z4lyDac zisuK~d>1xf6lU9bRrq||M!qFH1^T}eehTIGzVLYD>o3Bb3*&QP-XHLugZ3{&T&7LF zAM2sQhtTGVh5rDXlZ1gzm2eZ<#{%KEk+0>#{MPzbVIBi&{v_C6iMqH~w?i1!m03Hx7 zfj{3DJ^}S|P?+Dk{HgG}$nP(N`@)}>g!xg6L&A5!|96EKA+0|Np9&w;{6p}W-x&W~ zz8~v1h54nL_l1u^TK^DE1*>_3 zVCNc?c>&U6z78TSH75|bH}ZA7$cKUH6LqeK&NAT}kl!nWZ-x9u;r+HO~OofhcNB$5@wsqc5B(X2p;ISJ zA5Ir$`#D3HKCBU@oePEgK<6@H=4Gca+m)JY1pcrLe_+Ms^^!ghMLyJ=B4F0hTOwy& zd@jtm{JIzQnQmX<8&E#E!c14q1p*!VKT+h9m`C9UVW*aiI%Eio{15PY@|~i86MVZ}Hkv_cP8S#K!z_2Z;PD1{h18k zUVxpCMNZ%TL*(r52ww57l}U0LCrG(`E!uBQ4ZhO_SOo|0$(Z2w)YL;R`6co3&1}m!v{VK{gR9}#qgHM zna4kok=9YD(~m^Xa#iy~Kt3Mw1RVb+FZh0g(q91iK;cbbj|}_lNu4F^f$PZd;m^nm z@6XKh+6s}=ht*`H#e2(hL{1+ziJTwn-j z`lB4*B*Qktha#sBpOfK3Hte{lGwN@LPERuAyq0E&oY%|&B0m{CMC7l-{s@tu3wg1~ z*#;(vd>7cV`SpS_)75UWb7Y?w9Xek0erRa>EOL& z`1v33;bAiJ!0@EV>Hl+N`2PrOz9@3~|Axq4f&5*O)Bg`do{Zz_FCwS^?69DnV<1l? zBVGF6OXQ0oA1r(UcqkeE(El02CxA~DrvFW3*m)TGZDgd!utDVXe=8a3-VL3viJbml zFLGY%ZWKB18}AhPA0dB8I335^qoPBfpABAMm9(WfSJ`|z8 zz9r25hC{-3@a~xUe?*-!nENiAmKA4XjVL~|=}>0^)=b;*0O9#q7YSpf zu20lq7xZ|MlkvJz#hs1yG>c~l(+=<3j6bIeGj5~B%YXUPYX@8`}s$UB_w9os|AdhK;3Sl%C=LCzZ zg?T^8`&6T^`cx4YP1so>a&nuc&-+)SzuD5c)Z!hMKJROd{vE>fNA;T_E%LW4ect<0 zpZC2_2(!L;FKg~~UlykS>~E!<{I)Rbi(^74C%-TJ4w(18#*XT9gU->Ar-_`b#&tmc zGjO)Z$vMKj=Nx9S>X(B)?eiYm*qa494bF7GEb!`@E+&_U{&^{cl^W`T)hZ{UWEIst-`gfzJc9!}9-? z@B;9w7QZ3Pa`>&qe-!=|xoXYoeiZ$f^l z#XE!_gPhMZ=6UBf;T*{CviO_ACqTZ>;)jHHK(6`^aj(JfbCH*TU$FRP;kA&zZt>f~ z7eLPOHuQ)5kudG^Im-B%Bux8h7H106zUq^N9deGyX>*vxBZX<7&tt~EnzI~nX@9!N z$!gAW@vY9XqvlwGoObvuM>{MlHD@`P=UX*rxv-kE98BNToaMr5&T{bikn=gv*irqW z5_hM_Y4axGYVaP5?-AztT+LsOxa9AOoW~UVm}sATP7oB{bXi)UE+ zd=@qO>=PtYztQ4l!c1$G#T~*P%4KA&TazUuGAeI@nZvh?2*X1ag2_#GQdo`mDzT!Yl_qC!6PJzB3>Xhy2$Tzb3o{a@CIw9fnUtJ^=i=#SX3y zv{MUt4~u&W(+;1#O}eVD8~S;Wa|RB|$wgM&u@Iab^Tix*gN!xlFR z^Ln(>;xmP5pU?cp{wCq!kY8f)Wx~wwH5Pwen0D?F20D9%hl9Us@%MzOuln1O$1&h% zMLr#@`raWYzasL5;J1XCm-j3??1P~Hg^;Ux$HCN3z&VL>>L&>^UDZFI20&on5c>q! zt~`tLg+0jG2VwdyRKGp+d0b2tIl0o(XFr9}SM!cTpU1@#k&~BN`s}|j`fA>B(N}%@ z!fM`eu!p$p*D(5O-f_t3|89|!)x6`P&%O`p^SF3an8yYCGE85`v%&?Ct9Jp&6!|wI zKOM|I4x_K;7l#h-r9TrnSkT$nyzXYnp!mOuNFOkdM| z!aQ~!u$X;PrvFF1PvOCf@Qlb=R==|N*Oor}o{aqugclaQ@_8+ z$%BMFF#D~H{#ar9uimpjnS7k3&%Q0{^E}WX%<};Is!U(jGGWGDWpRhF2l*yT|6*bK z#<3=}Lssu)z|?2oma%`QrL))K`-PdVdUu1kaQ!dl!(|01y^oF>QD` znT{Z|V=;N>w($+O&x+?`O;?PcOoq(knkJ0TS;FsNt@0)Q^ZAW=*@3l3#&OP&kA>`E zT}YOE@t7e~UP?weGVquodswS-ko-=j9L(!xIT_ax240)V9@ewSQVz3)d7Rdgacna1 zI3!c9%8i*rI28-a%ENjQ8THQ4goW&3-IxHDIz6Av3P(_5lcY}7*dZws)ej)$kiq9l z$$LIo@;ja^c~sBZlCSlYOI~)9#een8D?YzUx%gQ!VS;CeBh9Tlq0B@$^4z-jBfUhV z#kyfF4n)m!mQLs5ofW||IgjX}^Lnk-bC=Hgj@mQLxwx>>xzpRWvtnp+sq3yBo176m zHu-vtNp#)7%G`UoE_^8O-ahZ=UXY0G+zYss1nJOwhi}Wjx5xYWXC#C?C*$Svg7Pe; z5yY&o&W{eAck6!6oq zoFB8@g7NF}SN#y|kbrz6B)F;}C+PVr6ZE8%n8uRd7f8@2gap2;;vKGP{t5c%kbS|R zQPOs_=JPyC6$Xlnd>lQ=$Fh~cq~I3(_TbO=v4ooN(@XvH5K8WW-(X7}O9|>%A6FSp z&y3&!{y(HToPv*C4lRv8+~woJdx4HR$g+YzD1f#)$b$Qsl+%lrgX)CmxCKfC0qe`% z#U5yNu(<_96_SDtz}`$$9h2_JZ^$0jp}Xr&Kh8)KN1O2V)aBxKR7w`+Ybwuj=O*IA zn?q4U+TIl71MAn_MMZ63ib+Us9v5x?coVHJCK#G(RC&F1+-YVXzRItY;TU4QuljPz z7}U-}00&{}ou{!B8F=1Tg`(wQBgg9z2uftK%6E^hgiAf&NDABgEHS*rgo!5_&0R$9rv@3eXg&aKx#h_s< zWfQFL`5x}8u(c80I)ee{%yl=Jjl)HpYZT&tKNw$GcYPa};~>G`u$(%)5@H1W7}yB< z8&T2MN2QS&PbuQ2mDT#MC_Q4KP$BZgYU|_J-O4ti74gZh37Uy~LD>32e)J9#Gp0N{ z?b7Lt)Bt?w?H5%NJsldmo#pQjIEOdWY1dI_q>jF{ABQtwGGw(aBkJv(nQ@gH`saW% zGu3KBey;DU(Q(y1q1v*Vi`ko@a@@Bsiz>_kZoDj^lqnIsR9Q^?y>z zN9^?1eH(cbW`Aq=3qDM2eOuW7{;#U&L{;g50+-+C#fvM~|IF`5clqGF+(ARHSeAEh z-ic$PzSw)bd-7m@LpN~pnn3E()dk@zZVIgRZVIG&)#$WzUHN9LeD~FS$Cm#V81uiK zhxsb|TyP8+Fj~*BESy&43g;G<)UOUsM(*O?P%6t#5Vs5{O>BNFZ*pTbEN+l zel^SgU{=hb67x-_m;*UxuYH*QkNiXvA0=>lRef{3=IK5Rk`CO*kc)+kZVnX=r#BpX zLs*Wa$Lnxxx>?Gy{xMhQ6JqpcVcT4%scG~oEv9@29;f(l%V#b=O;eBCjBBU67u&nB zm|*NRLSUHtc3Jj%$UfS;5DV>@z~|lT%m&uR#s-VIdk^d}FZ7RHVAP|%tFhSjIOgdo zeZzu1k$pSB#x~{e!`@^RI_=?+%C~n5*tYi|B5{no2?pp}?PbV5mdlG+OdO!|IqWSWNHF`J z!?ta&$kTCYkN0`Tzu$vR9H4V5dP*L(1P0%cIMiVX=ITCM+GBe)_WlZH9FxZZaC&Y` z`Eh>&er&xJ=(ju$auc|ZOC}a8x^pM=_{}R5403HX59beXsun_aDbNP}V>z;o+4d%* zz4%W+*k|kkqk=8}&;PEB>gV#)3-D#V6#}|L%a;UH%l0>sAJtFg3j(^Y%GzemBO#z# zfW2*>aacYm6e|SK%fojY3~W36ZcCxs(&v%hII|op+gvfVX|lZ=>)y-{ZwAeGpv_fI z$)dj&66c;#zLd^A_GL!**Jq-ug5hge46F7SQeyq?L5jBwBJ&<)0vX3P1J8v<-b$9@ z=Wf#%&ts2$>vv+U+7tLmG&q(E<@`Pvj|IMCD91XNEdBBSdSCtx2L8E zUx@XI!pV@cZ8Gjy@Iv7cST7R34Dw~dL&5FBXJUPpFu(b=P8ciaBH@9MUm@HEzCoDd zDjyZ*_{^UOb8P1`!nc865MGM)+rn!he_xnmHUBQmqUeD#VqVI@eT3_vGfemz$Ve`&h@9hN)mUE0Plo(*%2CPl!FP!c zng3gF+JG9f3m-U+^l8cwHx=t&i2h%(R{sMJImZ&eE^_AU_hiT)!1_~Rj@SJM88#n+ zP7f^9Ie>L48P2nv_9sJ!<;i-b&huE0AVa4bI^)RDVL6wRq4O!$m1NPWCPQZ`)(gnc z;s27UF}QNtSSmV2SgSF(&^Z}8Ybb|~hqTlfT-c$`X3C*+7Ie0gk=9kvxq}Ry$FOEF z^~iHCna2~N`3zOXJg4N6sen*`h0HcnWO1o*E!N{L=DCOZ^RS+7F^@6Id3>|JjeWk; zBlA4bY;lV)+f}>8UBWz$&$akG;gMKhZ1JVS^qu!HOpAQI@Hnh*wwUKg>P*7=UW>ma zJQ?eUEmp@S^ru1ggviN16=uGlx0v?~w9oQ+&EhwO+2;RXu{wUC&ocW=Uc+7p4&!=oIF~14S0gZlZDqpuEzZ%E}7r+pbso>zSl5Z zCwwL33oT~v5_MSKYTQ4VL7g|i4d8P`hrB_U{#aT))uEq0&dCZ+|@e<(<$oV}* z#wGJwMP~W%{AhTcFx!SYM?r_YRpjS@udw(U;f;{rWHGO8w7CWHdo127%=X6fHFXAn zeL3!IG;0QW8t}l!NWp*6HK~6 zk+YqLgn7KD3ez8D6LIN7mdH=W+7o8nd|}2d6lUBaVa6>LJ{9XSVU}$SGO58NkF&Z=@(P-YJb!j2 zY_=D9Q8OJ-gmW{#ozKZoI2lt_b%RP{XN8jya6=hECp9C{q5ag3A5LSAUDQ**mm=dW zLY1KmoMu9vgOMN5OX}-n>M;-0ymkK}9+pvoZQ*d^Ab5<$j)TatVyku$gg}jxz=4Jl z3~UD`@cJC2I6Zii9!HTLcbtU!e-IVvi^e?YR`F$qK75%m4~fBZkfMyBNDN+tjU-Cc zVU&=^rmeAftdFCo0(l@g!9daDSS6DKqljo7LEb~CNP%KvN-#M7Q>=OGCBLrX1obOl zF--{8j6oY_JvhPITk)F^3d!bNwHZj1%{sM-IRdp48NpLFA!b^u6FmJXMo+`!PQk@g z(xbbAjpQWdWw4nXO5=nA!DZwWEpMTVsoG+8;`r~-;z}oR0-e$sOe|jk%uwoy)5uxK zER$B5O$<|{iX|hlh1WQ(xq^uZuT+P-mbdX!O&sQnBI{(-RI$@_5Ia(WNyU8T>dF23 zH>%K-JV>?4Jk5Wxn%bMFev{O15A_>Tzsc%1Mg4O00US}k{Bi}FtorSxelyf>ruyZ0 zOFTuX-z@dpSN$HPe*3B4Z1vk;_XhMBa490FPu%jp+vzdjeEeo)^5d3zpE@5p?yxTI zM&M!R?izt=?!!4w++nN}6|(s2j^i(nJ$Kg%DDg=cLL$Ra{Mmzzer_F4ScJLm%zkdI zJBE#v6{PJP$DKSz-Cfkzi5+JW;{`^2t%pz73Y23`QVa9L&-e_y7NCDrmh@L|Lu-{- zRsO#|0>ljZNYcYAde|dELeYablA{N4qy*ibJty@%Rt@mzX@-PYqd&GcuwB7qIBT8Byaz`XH(p=QxopTQy1% zUz;+6P^fs69!YZbwEm;fwbIWTOp=W~PNqw7e~qFvz_wl0M~@L1sK_C%fQz6WdrZv6P#B5{x`j;#us%DGvn>Q zJ{K>$;^IuI`$d!Os%bau34QH59`lkKZ{H#_=E|hFI9BBoz?gp)m4SQ!a5L4~#`$R> z0fbk!HLd2%T)45~4U67^Glr_ez%ahJ4x|=Gy`CQDPB~*_l;k*fd2t|lGAC_KE)JYE zSxsm=yJlv1PR;arm_2khW+RhnRwAI3K51%QHRkS85{WmzYFeFR zPaTOonC}|fdh;5pW?Pe3VgjPWy!loWiK*FoW%8l0o>KJx|3Vg-526Q|Vgp>#tK5oy(LVI|AQGqw7e4sRedfdNA)+XKS zu$_;^1e4Y&5E$mZ9Y~k=_)M3NwA{yZFT`T!;}L8ZVKKqj*Z_fH?%QM8<8!XDcN3WQ z^j)!@Zz}`aCKwxEhrlrR?T0<~tI$6_S{i%%z_e$=r+`gn18ZYruf^Q`KJ2mlXb-QM ze0xuTZF}pm!S8dJVD>!*fw9ef6Hs`|A)r0=ZV79a-*Z?@9H28Fx13+I1P0%U(R&LO z$i7b#jNa=I*y-MkMzserrprD>?qj-t!D8Y7ojO!1%g+R}?*j;Id$VB3lrtZZjlC2^ zFmY((0@(8i63o6tfNgIr?3r@rW4W<62zn+CP2385d?#UoL4Lc`wznVl@}b21vb`F6 zBcR7PCXf98<>#cY6k@fH`^#eVN>Ev<6M#wx)Zvne#j18^CG@6nhXjLMo3_kdo6r@p z1H!>zQ+^p>9s{<$EVREi$V@Qy%(hwE^8bvnA8hLk^vRX3BPGC3z&~4Q$yXl>!XqIP z0;*K)ZMN7*`08^G4fIEk@F|;PMUEEpY%?4SQV~f`l>y&PFz_k7H)<)Yw)79nNZ;DY z72m%Y#=Q#r7t)w(t#vo#tC(wT>;r}JX<&*@pLrOFAK5g<40h=ROgJ^ z!tnt831A)<TM7`>57?u%E{e=Xc=uX4peV=6fUdrkVfw%_UP2p%4po_TYdj5xx%xz&PQ5BJLDn ze&2|Bp#JO7uM@rn`U{2EW4%b2U4F}ikA|Ig;eC)(k9IDG&F#YPfUgryg8#P(Plo>m>5cbj-_r+t1;>kq>0-~CWH2)TOK4W0YI>KqE@(UXPzFm55z z8Y(;pamNbtTT>0fzl3~|FwePbh0_stvoPy$r*Jm(IsXLhzXUt#oiLbXquv99uL3_S zI#)se6=A;D{H^f!u>M5&9F$uE_R(e*((NnE?`f%bxsVTo&0LWeK!3O}oA)T;C$MH& z)6U0OPZPc#YxOP{@=p<0jWGfD12>4yTkz#%;YF~yNSN=B)p!%=^SxuM$f2U=dVrkm zeXYpnz<)LG1LV)c{w9%g%#`}(8|3>T-y!n5!Roy( zQt!SWspBEybJu4@F`&RKi#mo9sH8WkAeTc6|RKbMV^^1-|zM$ zV?RSaIbHKe(K&#%dfzL@{_!GjgB>+r1N3tdMSZsoI{DyJsDpD0Lx(& z8F8mU=Ngf--qrWkpu_XbxrDtZYi$Eb2(PosBXwY4IM@#J!m;`i;83Z!u=@RxgN;^nQ5s*kj7dJcc8` zA6|}oQTzRH9=;6r!G6Apz5M{+6Ys33of?{1I3xc>%8J@UmD{|aldw;3C+-XNb29_` z(zfUCo8dW0Y4;YjtN&Yn(WwaG9d3HN^PM+tOC9J058SrwcJ6un_N+nWS>B+8jEq4} z7A5@e_JL(t7!>C@sqH%L+a&GKjKZ0omGVJ1VV~Yk+?ThdVoNA9;O1@#>}%SW+Wz+K zJ#L?V`!JP?wwW4bbGO)>H8Z2Ua7K=A6>pw%x8-hfg8TCJ<-A0X3idHaZ{N-wJ$`%I zy{YX%%W8&L<#!3Ft?h;?XU%9Y-&s*Ov%H+rqV~MaX&IXwdWaKh=8SwdY1E#fo0-=) z_Wo#Z)82}`S=ml7|7P05H@TE8o$pzdJ1hDQyPzHaoa_|Nq_u6ic>jfUXhz_H1Jm4< z*#l+;Qu3Yllw7CRzV_5Jf8w3sOdIZIQntq{PgpT*BVyyLL3q2*cn4G&oASW5J0UnA zS@!ho5I@Bp^hB+uKGPk{hqCUISC0aiRWp9fyukD#ezf$6!F^x$%;o2 z`3C%t_*F>~E&S=A4_q6CN%{T! zaAqSVNc+P~f$-w(?&6W;7spU_^U;gtm_Hd#eW;oFih9H^IOFbh)lOm&zI26emb(GfE9p0ZGd_fOI6;{3a zSmT#sK18DjC0Spf!MQgw%m`;+dvH?Jh@+}LUpVF{5-$M{X#Ju;Q&XLKJ<;Dm3~P>x=WGDtXjDJSwBoI%#mrNNP*OGAtX^X%#2UHHJWDH0mVvlB$y zVsez{t5o1%f#omc!-~bh^6YD;sj?hSO|%!CmJE{`5jzx$9*it@j_)5C_B9#(a!1GN zu~|v5hD^Cp{iJHY_30N^jVL$KWN)3>cAdor%{t0*y^)%A)ZWvK)U2cSo^GUO9p#nX zx2qJQ;(oE^MaH68M_G=Ou9e@fl5QNY*ae|N+*+{GjpLPHxUREEtoSSIt2=RPu-0fs zk8v~7r~-+TWy`TRnerW@@%o#LQL|2TI(m%B_r;0MdVAAoB{-$NijhUtahwwQ^0}gC zk&hTnM*{lx4L3>>*2$XpJq)~&VBlq$ffqgoUOT>OV8>*Fa~rM~{~Lw^wspoC2>AbD ze4u0XZ^a!B*rva^(TSmbxZ=v-K-6Gla3F3C@tOwvac<}P8VqA;?pU?BH6jsR+JH`* z*pdN*I=UGpq*ZXaS4|~wwA&SU0pAF?_q+vDa;J>S8k7Yrh(4pRZXUK#ThN> z+i9qpQ&}^w;lFgGTBM`D(NW(=^1Z2?Q`@l6i8El+XsE%@Y78WL!BlZ`)TY@Ru9;t1 zH)D3qNsbhyKb+J5&XNphWf65WFKg+<88plzbn%+SEv@m-5g4f&o;rVO)oj(W{#`@* zx}Ovx*{ZH-2(!7IgsO(K%i|0JwHnsE>Zn5j!yVU1iFL~O*29hdWT|inpBW~wa#=@M zjRQboM@EK54vDB?wv4O~xtPir0A!c-`ewOQfbScP2tlG(+=a5%l;*oVH9BkGNY4(-|Lnp=N}<^7GkXQn{H zf&$$o>S3D?4O~*O@cpuFZ!fmZBLvX5$9|p2!v@CKz}{rYJS_CZ*gFGk+Y4fY@2X8O zHku(Y%zf`!_E-+a-VU&B?^JAD1|+a z8#KY#cpn18+_ww%SXLeurq6w}$8XPA(VZqV#2OZ`1hbFdrLyf6p+Wu_J%k?gdSfy6 z`asXbp^5LHJ8HUmz~EM7AHQ{B>-{xNkNwbEk$t&PveW&z80kXbL6P0ACf#u{_R{bk zg!N&9NlSf8!w9i{WNf6}qsz*-$GJ029IDTQy$J*fW?v=1_AdhmuqkKsS^4%(i?O#I z_AZE1E(>Dp-3)uCUGbb^^4lWzO2waES@_mcl5Ajw-D>HI(YqJ@;>ShQd_B11pIf;5 z_t0BUBN7a9ZMp3{n2T=$K!BC%@TY%lUwq|d&S^l0Z*ppk5o}w?-F~p;{~2RSeZzo& ze^%5|c{A&)1oTJot!*A5k?_^OAEsUu_y+m?Fgpa)=);I4pg-j93j%6nvA>D@4EDQg zc#h|o(jk%EsvbC2(FE4Z6tjUfw-?52FN)c2kJ-K;X8Ri1Zos-X%6Cu9{s&{WpOS5M zKlR2H?cJFDe~sBT-?W>p^iv#;rDkAvRd1ZZ%(!QsBYU$nqB>c4V;6PL6UKjWg*!%% z4R^I+H9qFHlIn-M`<469*g>(~AGN~a)+Q?nJW=48(Z4e`H($|?9OFdCI>wLX-zi1k zmPSV(7ZZJ)A3f?$Dyokm>Yi6_!zhc2p^x=UX|_k9j5GOzfXj)KDb1JX6Eo&_0huSh z|Hs~&z*kjW?ZfBXdy`y3fFz7E-h==FLP8)QBH(2T$UG>bq9G&!qJe}YOo}on&hxC$ z3Qo1vS}JOts#w&jozzzA*rIK%Q!7}s*3$Yt&)RFByYD4{ec!%szwiJ5_V3|{ys4~U$`!4 zE0*4!m;)U+>X!OV^qZjZ9>8xKhoa+_dn@pQ2wo18&dvgkS(*Ax^gd*){U(}wE)6FS z!VW+>+20VK0L*eBeiHKMD1H(A?1M^9#ib5!Wk< z-vDMlQcvpjJH<~x=ARYQrskKHj&mE93;6Le&5J3fja811NNiWKwP-yw?s2z`!G z{0?|z90Gni`_1)fh^tC@x`C%j@khYdDXv9a+Z2yL*oPGtBCP$+nsxI{rJo8N{;0SO z!tPf*6?FRzHT!_RxTgM>0}oOBCUhR7_!l@&QOwuD^Az6$nN^C9hYqsW9^{-3I>$?t zc@N}Vq4-MhY*G9t@YrvbcOzbYKTrO@gZ{YUGr+%F@p$CJ3yMEPI$l!z7tpzR3B&Re zq~9v$z4blC8*%)T!IQ+)A9_AdjJ%%Hu+#L$gjB8vT9@ZcK@FCFP4y%+LOZ1#fAI^R+0qk+2;gHGKFl+J#vztWi& zvDphb>p+hy&uzdn6+Z+lc6y;tKJ?s3I&dNIC5jgU-$|_Z*@rdkuMqYr#h(HHM0pUM zv4soWUV?7SC+ax@xSiq`fcq$_#qh+`>pTZvsF?n2 z!?umzqL^)AyMymkd;-pF+m`=fhv!KL?^aCymlb!%`BlX+oZoivJBrEAHf-DYe#OlH zzdQIV#q)4x+qV3}xFlSjEgkSrdl1h^IOH?1L>%dgEGaP>QP2^|4u|Y9qUh3d09e(y- zg>b+qP3kjPj)$jK9sp5yX&b9s3hH+c&ZgVKCb#WGQA_ zW*xHfJ1AyeF@J4b>=%gH7GlK6L%IU|iJ4cTo9e)Ej7{SXA6WHyn^@BoX8vd!m$inP zuIZ$!{AMRV?Tb0PNa{#yq=pPWx^zg4?#OGTzUYrJ9?GQ*dNU=ZUNP3|d;wdbW1o#q z#1o)zR?!recZ+V|jm7U3-H3CBtl5cd&e+>(^W@FlJNh}}x5ajFolX3LybHF+{b#*r zqOd+1JL`5>9_3mq`uWJi>@|IwM#d&KHr6-BWa6Q+xpw)InEl!UQH)!;1RHNQ#qjcR zWnFb_d3|$iQBAB0%r(_9zB)GBayoiu26~$HNtu1UtFrd*9>+B89?v7`onOz`n~C*G z#M{SGpQqwcS)pXtJK42ag%g)f+Wr*z4s_eF<3M|VN3@(*?~FTp0>kZkP-MijkV2;E z4oxF5{gdT!{Z!$kc-*WX!_J}O+g$YS&hnU-e%`}v?ujDr(l+@4qjNBgDTW~w2nYB#|H+C1q4x`=5 z3U>TxM^VF_J9_V!xNX8VN=aFZH3@6FCPvG#s0wK-YM6deQNzUiQ2O+{P3Ybl{tw#< zG_-547I9CEO~`6EIF}jP+I3})+=e|)-SuQ!#!sFUEgu}u(sgQRaFKVmMJG}Vtmb-f z_gGtE+s7GMW*u4Tdal&#>YBxsE9=beP3F}w-olz$xaBp$XA$Ndh`YZk`xEPC0m#y) zw!!|WS(h90v2C-j2yKxCF<2MHe!)8FN7&&UV$ann@cKG3T|MGSVc2oBObm}BEy&w&M62dc#x#4Ie zt%T#yR`Ai|dco()@fljGTPJWGyi<+w(UcFkPcsGmYarqL~J97nOyNcz!JlcoC- zCM3tOC%F_#pSc-Kd}Q&`XKlwZSQeK)TQ0-8EG~VHTymmCLT0C*`fG&5vbglqS^Bap zF1?aW99%$L6>+-3HN<9FT>28?Ohd1widiTa-jv(Ci-YE4G?G!Ajfg~9b4*fS=nv5n^fCmS#c!v9=|z)bLH4xjveIKQI4JD z*jbKdk=jwVPD!?Pi5~qC0M`CRM=F^jWkis#G( z>|$zebbdE5L?U@Owv`2Ja-c|18A$42w1O1TB0E~UJ`j86cJQg#WfW`5FIrFI?os@4 zY+}$XmD4NC!zmJZ1V_Vh5}C8JTK8kGB63<6N@Xy(KNU4fw;n)!q9$DHfo~!lUmJLSnLid` zF?&Hw9)+wK3Ms{FFC3eAoQ1!?^+5#dAgiJ_vDVPZ`zC*r@Z+)*R$`q;HadCdgicsy z&pK5tU+no8KBj&$TKB%f@LS$Mb=7rKNGj76iLjWvVFO@syugv;_rMbFu? z@-d%X8Kw7T@08=Up+ZJe?A~Zx94CM4<#_rq8D8Ft1q9cDRn;%251sLyWO|3-(w0sE zS^UY{d4lU>^OqO?l*Nz{rZ}Na8hLYP=#v;nO0Zs!s}A^p z-1Fz2pdLp2TpMr7Wv9j_*p5HJN|A(qW@7UP+jK@E>~12FQy{Vp`$-dbm8~NaB<|-J zw-ia0Ro+Bal^l0)*|%mDYFag=__Gd<`5Z_!5jEI|#z;h^=u3^{hGfa9m$vLpL@N## zk!kOYQr-*tTOUFsre&OCV>fZ0W2H*Vcou9<%V0CO1EjA038t_P)f&)lq-5KnkFYhz zlh#0q(i+-(ZK#CFg4=BMFnN6?IuE1HZC0HQRf|0Tw&dC$c=lt${M*?(`KJ}yy3hW} z|Mp_Y>d&6UKdnD|7BdvNHRx`VD*rjqcD6~db_Ov>ITs?NGeA=OQJ#cgyRa3=q~ShW zTBhzlAEerg6S7iL# zcBaJd(4U~4AWqys$PQ2kiIl8y+d*O9VKf$EyWWhEJwQ8YR)$zWA{%NuRt(1{x{BGt zYUOA;5X@e7Zx&TM$u$wu=1%Iu>~6;lHicS7!=SHzk{p>6HL*mh=N zY__{FHpg9~X_m!uC2U)>n?LUUu7A?fS8T}Tt~KqL2qnAkC$B8+Y!7)736zX>KnrzCFHu*->1H8*>-S=GhC(sQUi#?WtAo zJS-Y!Gr-zdn|h|B50}u+@lWh**X;In5(dFoARDmbvd~>|OS%0;arg{KR@K-RNLnFl zNJZfF2KB|E*bTw;w1G=nhIpDKJJheSsPgngFx;4pb5?35uTM-cw8WdVSTm4&C<%eS z385TUiaVm-hY~u+l`!X4du7i~);Q)BTJ#O{PYM%ITL^PRrJX1pq5tKi%uVP}VIhSb zywKH&%_&+N##!-usNg|qC&K*q%PNrI=gKFv)Lj|ZbsCIc(-OB13yeC&{3w#%c=jC9@HuAKoxf*XEu)-R-42(Hmwfcf< zXPGyuT+-rhY{!c*cvQfv3bQ<$?<|tnbd#bnCs>jff+v=H%K~u3g5CG=Vh#Lwo~8gU z39M|c0Rd{0VC?eAqH&BSr9p%@`u-_Jqw>QYHjNH9#0D4ThdagwjXoZ)&i!B^_)vfB zAWX?72qXQI2aO&xdfTZ<>&2h-{9D5fQ^MKBkQDAXYGnRNNuhr3>B4Or_sgDtbupHE zPshUX(r)>A`B-M2B=KEr`O~X7Z*<@AS+VJ5;j@Z+7WC+ymzTV3{1eaLR5G=951PC= zt2n=V-);pd90xpqamltpdB-NHv)%WbM^7#3SrEQ@{gm*2ypeYozu#w9nOkLdT7qK> zLXCGg;yONvnnBqxN7yrI@>LmN^FNnTHO+a%j{%TFsCkiI3Gy%djoPwX{Kd zGr{sryY^VBB-dm&VeP5a(8Fcz~MMS`W=wDanQnLEy|>2|2JbhJp4oLt=h zV><;nagU$u>PH(%+FNlAeoa*~%HQFpNg}R&7n5DKmZPef4H=}@ti`qp6|+yAc;ZBN zDSeP3iM8#C{Qy{HO~08iC1!;~Tu{M-%^9eX>2$@I6vNB?h_%Kkg@e}bJ1GH7Vzo=| zWs8O&M%f>L;!Q)c!z8IqPNF^R?2*`q0(-s$yF~<&>}D=4+Z|Igc;%DqcuqGeV2*k# zR@SV<_9D1rXq zii*W6mseFJ-F4YhnZ#fp3oXX#+NMN}Pn5WoF6`VXM0W(cYWvGNNUu zX40HYGZxPhk#N+;{`o(%uS1fRM4R4}9Tg554;|ht7xsd1>Q{=agQ`S|e+z|}!eJVt z&9xRi?JciG&!lGTaI`cGbG%t#a%XjD2e03BJQ*P9mu!yN3Ryg4*s!CqIfXHA=1_CcMwP9D+Nz#ymktP5#ae%T#c?wNe7W+@$F-fx0Sx3#cQEOXJM!?hT=*z&8UBE6PBnjmwq=~#zLi|O+m;-$P2{PA8gi1(YoZaNBa5eLmWE8}JmET&)f2(xyB z^6&~GkoN?zE05p*x0ElBXc(NtO@lm}&+_dysJz~TzbkJIF6@*TyaJuxbTH}jA+G>u z>emi`>P~t8z~7bkQ(Q~{%{rULFF>%Ee(M~0IqFAwT@l`u$IrRqpj&5UbOe*d^xNjh z!#kHizfmdjWQm&=21`rjdq#@9QO6|8m+ytFewU@ld+QMLE=-X(*^$RS#mc)?&Y zgDHIMKw9E^QTeQh4&WPXg*) zrC0Mvtj9w`qr5!)ZF>IKX!d)-MZuuDrS#*e3=&l*c!QR$iYJd6z@p2KZZN<;7CuMQ7q0 zFL+X3A^uk0h!lBk@DbIC_GSV;E01=lT>a+HGJC5~9^a;0dE8%yVc5p#7WIH_4|b&L z=*R!e6uwH_pzM@ASuG#?5Jw&FR`AV7SnJ3~$FoEBw&6y$hjkEiTd&yusER9Z!?5If zYUP0~$+`6Z{k>3HN#9I`a`E@g=Q4qQVe`qZbIm(L!i9s-hIX)hJ@%{#7e>#BViU)< z?gv+f_V3s$#YnR9SV9RGmX_;Y_fA{@g{6fhNMUIq?lo(8!iCM}DFGpzWSNxm1_k#2 zP_2>25pQh3ZTjs=dd)h-y;T;Z_;XxB$JbM|54c{g%zz#TX$2k|} z`&^3uYbn>iOS%3_%5^KPz}6CRIg2Xjxy^fl!5-8 zv@CMfoKHzndg zc@xe)O(w!6Jwmqh+$cJ_uM|j-r^n>v54Ss1CTn1};5qo|Qp?HNnw4^chfG^WGMUJG za88UB$Lvv;oo_Jv$D9I#NwRi0*#mWxj~DrQ9C-Q|9t;<~914TOkipBw{fv&)GpD~m z8DHhdCu(M0XpY7;m^=dw4~98jHU-0_5=M9tY0G zSdmWBd#r;;8_eh<6b#n|f4jzWGO^O95mNx%Qv5BwjyOuH8FyLwHeB0vtS=I)oL>?1 zfevmj{+7O2iR55~^Jo`n8BR&lSBY7qQ7DF_o!;zn92v43RptV-~GQzf3{1o_kFDB2Aq5n|DXF`A3 zQwa2LB8|r>{dd3<72g7$X^QWGe5qI9za8`?O6NE4s}$3|>jjEAqWYHNi-BeBKf=lVcm5O%xbUx5E^#r2@mmN9kX-dqnUJ|FS^Q1J-hrxo)P{+}p*18L+wRt!59SoTl? zrp|v+I`{1PN^x80(;9#BUl0B+itk50_g35;VM`Q$7rISS{B7jPT*VB#P;oZsb&9_O zIkImO17Xja`coy)p#L%7Ybz<=U9Qa+up8$WPn0dQb`LjXqfN)H2HS($_ zG0t>H6GKiZ_{$Z~1fHt=bCJdqi8~tpQ-~3kW0qx#c^{L#l9cB{(ou$VHz^OFZDfBW z=&%fWJx6+`uz0^F2E7yHzC#Rs&ZGW{?*RTxd2RvzO6jtf8{%PDmTy~PgysBFd!@4+ zdnmmSZMrWp;^pml05R^-bjK)9Ie5k?X5ThdF~iOxM%Y5|FHuZ6G{;GL9QZn7=raoO zev??oIcyK4b1CZ&h@t0Mkol})?)@hFDS@9un%^t`pTPfTVjUM{AdeW9i>$JUAros1 zB=1P)-hJJaen04al%M@snc_}p)5j1)CiP#a{L_(#XAtWY$a%_7d-4}4597K<>2pB8 zQR$3pyV4s#-$@KPl>fZ)+<!H!-0QF3_T}6=Bvay=KO=wSOU)l2#(TblFH+2SuXOOWiW%=M4*sTM#(SrOzpa?@@_xqjQs$G2 zN8l4K|nP&&(XW84Z|5QwV-v6xp4vHzin}fMbm^|d? z{mYaCpwcr@q@4sKRV`Mm$x`{RX* zd8@j@!Ph8`gU)-T<(ECm(B8=ZJ%?YOQ$S}qKB{zL&L=YLalp?w_<6-~(B)nW9=hKu zo$@)RXISD79e&<}tv;N*usj(KZmpO)^cCb9xsC;>TQTb;&@_BEz_imbjBj#;Uo>>%MtaR2B-oGvXtq#BJSEl^m zark-vw)ga1ig~;Fv4el2_yo{-U$^|fQQQgiKREaUhhLsw(67-QP&&&fjQbzu5N9Z+ ze2xi7?+Gk>y#mL8xfKTK#C;rojtT5IL7szi;#Wjkl!_5x|*)lIS%6! z@~?OJ&vW=Wrm_5-lOkq5f5XAs9e$2!$WsKK2Nd&O%CU$YtNd6os)YA*2fwVC?UZ8? zJ3e_|G5J4nF!xO+5BYhEigd;Sj&;=DyE(6C?=LZ8j63KG@n`=-$1<~h0>@#t{lnY4+XtfQ3Z`D7Gw#K75(b!Y z#_+dkDNxL`GK@_Z^PPAK&XO)oBkygDD~_|I5q%xqDEygr=3$(eioi|4pO}5lWMa*S zX^QDD`M`j1Yd|>*_-CXkJw-rkth3I*zSVOtB5bnupDbN$<&iQuAjV zF$*7VE-}(hS4*sExBWlqw~(%Be2iGrwTD>Kf~7e@`Ep*&>O7oS^_)bkx|Ng;J|^b4 zBkhqmba>e@!-fCIdnA@2^SMg{%a0{p?v2OZgP~~5Gy4TjF6Ul&g_FALesBW zwD~k|GdaB+-#6U7?`K@M?Me-wNDFraoLrv0-t1MF{Teyn-ErGCa_km;y|KIFOpDQ) zadUUas&NOpMmOvpOCRGex;|z0OMGe9o^$uCvAJMEWPC7wV>{H2*v7x_%W4Sijm7t@ zXKZGV!RH=gc(ZF{>oqU!+7-+9_pE;*mgmvm8<*Ib(%q*qv?KF<6Qj}OrCmPsadmLZ z4QVYm`zIp5`gm7m@3*Pmt-BFMnw_+aHNH{FlXtdxW2s?eS@Ir`QwqH1E#u9eh(!%| z$2No_x#3XSN0sNbK?^Tfk+nJ;q}1e{NoRZPuE{+K_x6=0=Y{rWH83}rbIpxwW6kw3 zezJ_sFqg;dyVaWNn0|2|>%+FpeKl7uH}8+D?S`7M+G=cqumCJ(zEGWs_{fnTVP4_U*bu_Q;H6M|79a=)~<$om}8WFWmFA-^SaoY1u7x-&>RI z?eMGp9ex4+Py2Uyi#IQfGxZ0$?ZO_L;T@U%61#SiUevHXeo0=$D}3X)y}ZUgP|^;v zwWY?LG^6Din_~}!?|SF1(1k?}`FA~iXXg7M^hfQY{bPl1H?~W>lS1b`k=*;iY~303&Rvv3{_bx)y*WCm)t~b&$oQc5#(`^p z7aQlj5Ze@{-#enuQ}H=_<9*t7`dLHz=JsvF*^$kW&VDZapIPzOeUcX{DOw)c9DRT6 zhV&07Y?^x3yRl8)Q;>ieoxLUfz6$rdOQ)@-q`HO!?Y$jqq@4Ee+q1^>4;T`yV7#VRNc3?Gffgn` zjp^;CNlWp1#-$t*{UYV0wnyx~i1v8xNBD3uvW7r?>EFd>|KgoUn#T0YnL}{-?nSVrfuhKjEmLu^}C zLvnvg>6B{v>JF>3R-n(4o;vv6BIT17-uf9cmJqM&mDOFwNGxf(Ir#J49`;hb)t5m< z^1i2Nu?OuPDr2c23_03z?@)GSZL_w7BQ1rA!!r?25JmvQP+aOBr7}(n;^BZNSvMP| z5I)uo07#8z3v5_}Oz|?dw7h-E%gk~1k#%M9d9wvsR77OCyqq^m@Jd!h-FOGX-#Qr| zevNc>w*hcwc*$7N)u`acPn?L~y{=yG}5mh>RAT=_@J3s-(i zWq|r|P+7a_>yVT_Q(Uf0js;WG=gPDRb!ARYl4&?xnTrmV$-Rfkn6&q>8%DX>EaZU zCyB6mpa^s0MwJ>auA#plO;Ac#lfrK{EKk|Rq!{60v(0Tjm@O8)kLo zxK55|%keBZu9f2&Ibxez(KIsZMuff%Mly^jk+A5Ul$ODm#1hgP`u(gqRYrAvf) zA)IN&gu)q38_d~I!&yqGc!*4rB9u(DQb5|!0r1X@EXJ|*nK)=Jq(#z;`PHK+X^tir zLqZA5G2(%3)EHEZ!?THRnjF*Rm?6ig99zjTQ;x0Wm?g(Ha%?L{e!qjKeL3dHF;|Y< zW7E7z#d{0Eo#fbAj$Pz<6qL+3y5cZOnoJ92%)A*)^2C@is}6FxU$D8HEtl9Y*j&z$ zOFleGc4udt`Vm65sq->UXU2MMurxKJl1yf!{fsJN-JiFHINGMJX1SNKgqSbRQ1rD_ zG0WDlwk!+A(2k-zn~1Q(F1Lbf!yR_1t0~oJoK?i^;2V{i)4{M~hh0wWiTLO&3R66% z4`3IRI%!gQq7{^phK+Ce`GVxz22;`-&1sW4oo7zxo6}}&rx0KX@3%8a~#qhvznNn{qqBmS}M zFGQ|Cst?0!iu}oOc%ZHM$4gr?EK{hSQOTc5cB7I%jcLpB+DH8p{c42c4cGHe@+GLb znD0}Yho#w%K0FGQ%W-MCq=@iTm({zc^5558_^)~xkH19@%6Y@s3HEZl>72z`jq zjqI)>y9|Ctc2`HX_~|C3Y#(OX;?{40S>8+gr4E}40B>dQQ%i^*oM3mA?rkB0@w zv~Pfr&wYgRv32M)uQ%!In3N-_&( z+bjsOn=LBH?zqgidykoH;CvySiFy?whoSz~l|j_2Y+Qrr>#yNu=+bqPnJt-R{bOTShsK4A&;K2!LxcXDQgjm89CqIqO)NhTGZ~lV_!9-`7c(z_3Qy>k`UJHMu!ZcR&rc=nX236d9F&47#zF zp6j%lUkXiIP29AmqoL6smG_*8p|NN=PY+E|%M;}x!rA<~8&A{xMwsTuK$_=w2g)+f z{H+yWH_1r&45;<|?*x1raHoF{Sm_G!_qX!O1l$?0nhbt0xR&B#wmHT1P8wbYQ;h!u z9{JqmZ@nIG2Fj$geqfuNX&OJUm7nj>JpU2aPk%TugP6K_G%s(!KOJ-Um`222+0Whr zU%HrVU;SgNI(r+>e@VJMAPLFdydleWDlcq9NYQ(;)Cb-3+_o_66|TW%0DOpGM&w&^ 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 JJ-ehb{{>&+Bu)ST diff --git a/variants/arduino_101/pins_arduino.h b/variants/arduino_101/pins_arduino.h index 631c35cc..e447277c 100644 --- a/variants/arduino_101/pins_arduino.h +++ b/variants/arduino_101/pins_arduino.h @@ -25,7 +25,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h -#define NUM_DIGITAL_PINS 22 +#define NUM_DIGITAL_PINS 29 #define NUM_ANALOG_INPUTS 6 #define NUM_PWM 4 #define NUM_UARTS 1 diff --git a/variants/arduino_101/variant.cpp b/variants/arduino_101/variant.cpp index 0fe85c2d..d9b0bf05 100644 --- a/variants/arduino_101/variant.cpp +++ b/variants/arduino_101/variant.cpp @@ -82,9 +82,15 @@ PinDescription g_APinDescription[]= { 5, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 13, GPIO_MUX_MODE, INVALID, INVALID, 13, INPUT_MODE }, // Arduino IO17 { 6, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 14, GPIO_MUX_MODE, INVALID, INVALID, 14, INPUT_MODE }, // Arduino IO18 { 1, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 9, GPIO_MUX_MODE, INVALID, INVALID, 9, INPUT_MODE }, // Arduino IO19 - { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 - { 24, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 58, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO21 - + { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 + { 24, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 58, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO21 + { 12, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 46, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO22 + { 13, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 47, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO23 + { 14, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 48, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO24 + { 26, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 60, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO25 + { 1, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 1, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO26 + { 2, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 2, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO27 + { 3, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 3, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO28 } ; #ifdef __cplusplus From 5340b0c9c1fa02257b7f363339594944f4c6be9e Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 5 Sep 2016 15:41:42 +0200 Subject: [PATCH 096/222] CurieEEPROM refactor This PR refactors CurieEEPROM library, syncing it with AVR version. Since EEPROM on Curie chip is based on OTP flash storage, the minimum write size is 4 bytes. The current implementation brings some problems like http://forum.arduino.cc/index.php?topic=421348.0 , and the examples are quite broken. The refactor also changes the name, from CurieEEPROM to EEPROM, so code for AVR sketches compiles out of the box. The new library resolution engine (from IDE 1.6.8 onward) handles this perfectly but we can stick to older name if we need compatibility with older IDEs. --- .../examples/eeprom_clear/eeprom_clear.ino | 25 -- .../examples/eeprom_read/eeprom_read.ino | 40 --- .../examples/eeprom_write/eeprom_write.ino | 38 --- libraries/CurieEEPROM/library.properties | 10 - libraries/CurieEEPROM/releasenotes.txt | 7 - libraries/CurieEEPROM/src/CurieEEPROM.cpp | 222 --------------- libraries/CurieEEPROM/src/CurieEEPROM.h | 178 ------------ libraries/EEPROM/README.md | 139 ++++++++++ .../examples/eeprom_clear/eeprom_clear.ino | 39 +++ .../examples/eeprom_crc/eeprom_crc.ino | 9 +- .../examples/eeprom_get/eeprom_get.ino | 4 +- .../eeprom_iteration/eeprom_iteration.ino | 57 ++++ .../examples/eeprom_put/eeprom_put.ino | 5 +- .../examples/eeprom_read/eeprom_read.ino | 56 ++++ .../examples/eeprom_update/eeprom_update.ino | 71 +++++ .../examples/eeprom_write/eeprom_write.ino | 60 ++++ .../{CurieEEPROM => EEPROM}/keywords.txt | 15 +- libraries/EEPROM/library.properties | 10 + libraries/EEPROM/src/EEPROM.h | 256 ++++++++++++++++++ 19 files changed, 701 insertions(+), 540 deletions(-) delete mode 100644 libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino delete mode 100644 libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino delete mode 100644 libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino delete mode 100644 libraries/CurieEEPROM/library.properties delete mode 100644 libraries/CurieEEPROM/releasenotes.txt delete mode 100644 libraries/CurieEEPROM/src/CurieEEPROM.cpp delete mode 100644 libraries/CurieEEPROM/src/CurieEEPROM.h create mode 100644 libraries/EEPROM/README.md create mode 100644 libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino rename libraries/{CurieEEPROM => EEPROM}/examples/eeprom_crc/eeprom_crc.ino (88%) rename libraries/{CurieEEPROM => EEPROM}/examples/eeprom_get/eeprom_get.ino (94%) create mode 100644 libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino rename libraries/{CurieEEPROM => EEPROM}/examples/eeprom_put/eeprom_put.ino (92%) create mode 100644 libraries/EEPROM/examples/eeprom_read/eeprom_read.ino create mode 100644 libraries/EEPROM/examples/eeprom_update/eeprom_update.ino create mode 100644 libraries/EEPROM/examples/eeprom_write/eeprom_write.ino rename libraries/{CurieEEPROM => EEPROM}/keywords.txt (70%) create mode 100644 libraries/EEPROM/library.properties create mode 100644 libraries/EEPROM/src/EEPROM.h diff --git a/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino b/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino deleted file mode 100644 index 07f6613c..00000000 --- a/libraries/CurieEEPROM/examples/eeprom_clear/eeprom_clear.ino +++ /dev/null @@ -1,25 +0,0 @@ -/* - * EEPROM Clear - * - * Sets all of the bytes of the EEPROM to 0xFF. - * Please see eeprom_iteration for a more in depth - * look at how to traverse the EEPROM. - * - * This example code is in the public domain. - */ - -#include - -void setup() { - // initialize the LED pin as an output. - pinMode(13, OUTPUT); - - EEPROM.clear(); - - // turn the LED on when we're done - digitalWrite(13, HIGH); -} - -void loop() { - /** Empty loop. **/ -} diff --git a/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino b/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino deleted file mode 100644 index 2682d2dc..00000000 --- a/libraries/CurieEEPROM/examples/eeprom_read/eeprom_read.ino +++ /dev/null @@ -1,40 +0,0 @@ -/* - * EEPROM Read - * - * Reads the value of each DWORD of the EEPROM and prints it - * to the computer. - * This example code is in the public domain. - * 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan - */ - -#include - -// start reading from the first byte (address 0) of the EEPROM -int address = 0; -unsigned long value; - -void setup() { - // initialize serial and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } -} - -void loop() { - // read a dword from the current address of the EEPROM - value = EEPROM.read(address); - - Serial.print(address); - Serial.print("\t"); - Serial.print(value, DEC); - Serial.println(); - - //increment address - address++; - if (address == EEPROM.length()) { - address = 0; - } - - delay(500); -} diff --git a/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino b/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino deleted file mode 100644 index eb55d180..00000000 --- a/libraries/CurieEEPROM/examples/eeprom_write/eeprom_write.ino +++ /dev/null @@ -1,38 +0,0 @@ -/* - * EEPROM Write - * - * Stores values read from analog input 0 into the EEPROM. - * These values will stay in the EEPROM when the board is - * turned off and may be retrieved later by another sketch. - * 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan - */ - -#include - -/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ -int addr = 0; - -void setup() { - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } - - for(int i = 0; i < 512; i++) - { - unsigned long val = analogRead(0); - Serial.print("Addr:\t"); - Serial.print(addr); - Serial.print("\tWriting: "); - Serial.println(val); - EEPROM.write(addr, val); - addr++; - delay(100); - } - - Serial.println("done writing"); -} - -void loop() { - -} \ No newline at end of file diff --git a/libraries/CurieEEPROM/library.properties b/libraries/CurieEEPROM/library.properties deleted file mode 100644 index 0f3c1e2b..00000000 --- a/libraries/CurieEEPROM/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=CurieEEPROM -version=1.0 -author=Intel -maintainer=Intel -sentence=Enables reading and writing to OTP flash area of Curie -paragraph=This library allows to read and write data on a memory type and area that keeps its content also when the board is powered off. -category=Data Storage -url=http://www.arduino.cc/en/Reference/EEPROM -architectures=arc32 - diff --git a/libraries/CurieEEPROM/releasenotes.txt b/libraries/CurieEEPROM/releasenotes.txt deleted file mode 100644 index d7c6e2cb..00000000 --- a/libraries/CurieEEPROM/releasenotes.txt +++ /dev/null @@ -1,7 +0,0 @@ -01/05/2016 v1.0 - --Initial commit for CurieEEPROM library --Implements EEPROM functionality using an available area of the ROM --supports both BYTE and DWORD reading/writing --EEPROM[] currently only supports reading --an empty DWORD cell has a value of 0xFFFFFFFF diff --git a/libraries/CurieEEPROM/src/CurieEEPROM.cpp b/libraries/CurieEEPROM/src/CurieEEPROM.cpp deleted file mode 100644 index 3127f18f..00000000 --- a/libraries/CurieEEPROM/src/CurieEEPROM.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. All rights reserved. - * - * 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 - * - */ -#include "CurieEEPROM.h" - -CurieEEPROM EEPROM; - -void CurieEEPROM::clear() -{ - //erase the 2k bytes of the eeprom section inside the otp area - *(uint32_t*)(ROM_WR_CTRL) = 0x4002; - //wait for erase to be complete - //TODO: while(((*(uint32_t*)FLASH_STTS) & 0x01) == 0) //wait for FLASH_STTS.ER_DONE to be set to 1 - delay(1000); -} - -void CurieEEPROM::write(uint32_t address, uint32_t data) -{ - //make sure address is within valid range - if(address > 0x1FF) - { - return; - } - - uint32_t currentValue = read(address); - //only do something if value is different from what is currently stored - if(currentValue==data) - { - return; - } - - //allign address to 32-bit addressing - address*=sizeof(uint32_t); - - uint32_t rom_wr_ctrl = 0; - - //check if address is available for writing a new value. If not erase the whole 2K block and re-write the rest of the data - if(currentValue!=0xFFFFFFFF) - { - //read entire 2k of data - uint32_t blockdata[EEPROM_SIZE]; - for(int i = 0; i < EEPROM_SIZE; i++) - { - blockdata[i] = read(i*sizeof(uint32_t)); - } - - //update blockdata buffer - int blockIndex = address/4; - blockdata[blockIndex] = data; - - //clear EEPROM area - clear(); - - //write back all data with update data on passed address - for(int i = 0; i < EEPROM_SIZE; i++) - { - //store data into ROM_WR_DATA register - *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; - address = EEPROM_OFFSET + i*sizeof(uint32_t); - rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) - rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit - *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; - delay(3); //give it enough time to finish writing - } - } - else - { - //store data into ROM_WR_DATA register - *(uint32_t*)(ROM_WR_DATA) = data; - address += EEPROM_OFFSET; - rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) - rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit - *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; - delay(3); //give it enough time to finish writing - } -} - -void CurieEEPROM::write8(uint32_t address, uint8_t data) -{ - uint8_t currentValue = read8(address); - //only do something if value is different from what is currently stored - if(currentValue==data) - { - return; - } - - uint32_t rom_wr_ctrl = 0; - //make sure address is valid - if((address > 0x7FF)) - { - return; - } - - //check if address is available for writing a new value. If not erase the whole 2K block and re-write the rest of the data - if(currentValue!=0xFF) - { - //read entire 2k of data - uint32_t blockdata[EEPROM_SIZE]; - for(int i = 0; i < EEPROM_SIZE; i++) - { - blockdata[i] = read(i*sizeof(uint32_t)); - } - - //update blockdata buffer - int offset = address%4; - int blockIndex = address/4; - uint32_t data32 = blockdata[blockIndex]; - uint8_t data_array[sizeof(uint32_t)]; - memcpy(data_array, &data32, sizeof(uint32_t)); - data_array[offset] = data; - memcpy(&data32, &data_array, sizeof(uint32_t)); - blockdata[blockIndex] = data32; - - //clear EEPROM area - clear(); - - //write back all data with update data on passed address - for(int i = 0; i < EEPROM_SIZE; i++) - { - //store data into ROM_WR_DATA register - *(uint32_t*)(ROM_WR_DATA) = blockdata[i]; - address = EEPROM_OFFSET + i*sizeof(uint32_t); - rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) - rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit - *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; - delay(3); //give it enough time to finish writing - } - } - else - { - int offset = address%4; - uint32_t data32 = 0xffffff00 + (uint32_t)data; - for(int i = 0; i < offset; i++) - { - data32<<=8; - data32+=0x000000ff; - } - //store data into ROM_WR_DATA register - *(uint32_t*)(ROM_WR_DATA) = data32; - address -= offset; - address += EEPROM_OFFSET; - rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) - rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit - *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; - delay(3); //give it enough time to finish writing - } -} - -void CurieEEPROM::update(uint32_t addr, uint32_t value) -{ - write(addr, value); -} -void CurieEEPROM::update8(uint32_t addr, uint8_t value) -{ - write8(addr, value); -} - -uint32_t CurieEEPROM::read(uint32_t address) -{ - //make sure address is within valid range - if(address > 0x1FF) - { - return 0; - } - - //allign address to 32-bit addressing - address*=sizeof(uint32_t); - - address += EEPROM_ADDR; - return *(uint32_t*)(address); -} - -uint8_t CurieEEPROM::read8(uint32_t address) -{ - if((address > 0x7FF)) - { - return 0; - } - int offset = address%4; - uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address-offset)); - for(int i = 0; i < offset; i++) - { - value>>=8; - } - value &= 0x000000FF; - return (uint8_t)value; -} - -uint32_t& CurieEEPROM::operator[](int i) -{ - return *(uint32_t*)(EEPROM_ADDR+i*sizeof(uint32_t)); -} - -int CurieEEPROM::length() -{ - return EEPROM_SIZE; -} - -int CurieEEPROM::begin() -{ - return 0x00; -} - -int CurieEEPROM::end() -{ - return length(); -} diff --git a/libraries/CurieEEPROM/src/CurieEEPROM.h b/libraries/CurieEEPROM/src/CurieEEPROM.h deleted file mode 100644 index cfbce2cb..00000000 --- a/libraries/CurieEEPROM/src/CurieEEPROM.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. All rights reserved. - * - * 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 - * - */ - -#define ROM_WR_CTRL 0xb0100004 -#define ROM_WR_DATA 0xb0100008 -#define FLASH_STTS 0xb0000014 -#define EEPROM_ADDR 0xfffff000 -#define EEPROM_OFFSET 0x00001000 -#define CTRL_REG 0xb0000018 - -#define EEPROM_SIZE 512 //EEPROM size in dwords - - -#include -#include "Arduino.h" - -class CurieEEPROM -{ -public: - CurieEEPROM() - { - - } - void clear(); - void write(uint32_t address, uint32_t data); - void write8(uint32_t address, uint8_t data); - void update(uint32_t addr, uint32_t value); - void update8(uint32_t addr, uint8_t value); - uint32_t read(uint32_t addr); - uint8_t read8(uint32_t addr); - - uint32_t& operator[](int i); - - int length(); - int begin(); - int end(); - - //Functionality to 'get' and 'put' objects to and from EEPROM. - template< typename T > T &get(uint32_t addr, T &t) - { - //make sure address is within valid range - if(addr > 0x1FF) - { - return t; - } - - int byteCount = sizeof(T); - //return if object size is too big - if(addr + byteCount > 0x7FC) - { - return t; - } - - //allign address to 32-bit addressing - addr*=sizeof(uint32_t); - - byte *bytes = to_bytes(t); - for(int i = 0; i < byteCount; i++) - { - bytes[i] = read8(addr+i); - } - from_bytes(bytes, t); - delete bytes; - return t; - } - template< typename T > T put(uint32_t addr, T t) - { - //make sure address is within valid range - if(addr > 0x1FF) - { - return t; - } - uint32_t rom_wr_ctrl = 0; - int byteCount = sizeof(T); - - //return if object size is too big - if(addr + byteCount > 0x7FC) - { - return t; - } - - size_t size = (sizeof(T)/4 + (((sizeof(T)%4)>1) ? 1 : 0)); - uint32_t *dwords = to_dwords(t); - - //check if address is empty and available for writing new data - bool blockAvailable = true; - for(int i =0; i < size; i++) - { - uint32_t data32 = read(addr+i); - if(data32 != 0xFFFFFFFF) - { - blockAvailable = false; - } - } - if(blockAvailable) - { - for(int i = 0; i byte* to_bytes(const T& object) - { - size_t buffer_size = sizeof(object); - byte *buffer = new byte[buffer_size]; - memcpy(buffer, &object, buffer_size); - - return buffer; - } - - template< typename T > uint32_t* to_dwords(const T& object) - { - size_t buffer_size = sizeof(object); - uint32_t *buffer = new uint32_t[buffer_size]; - memcpy(buffer, &object, buffer_size); - - return buffer; - } - - template< typename T > T& from_bytes(byte* bytes, T& object ) - { - memcpy(&object, bytes, sizeof(object)); - return object; - } -}; - -extern CurieEEPROM EEPROM; diff --git a/libraries/EEPROM/README.md b/libraries/EEPROM/README.md new file mode 100644 index 00000000..a6241361 --- /dev/null +++ b/libraries/EEPROM/README.md @@ -0,0 +1,139 @@ +## **EEPROM Library V2.0** for Arduino + +**Written by:** _Christopher Andrews_. + +### **What is the EEPROM library.** + +Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips. + +### **How to use it** +The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch. + +```Arduino +#include + +void setup(){ + +} + +void loop(){ + +} + +``` + +The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below. + +You can view all the examples [here](examples/). + +### **Library functions** + +#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino) + +This function allows you to read a single byte of data from the eeprom. +Its only parameter is an `int` which should be set to the address you wish to read. + +The function returns an `unsigned char` containing the value read. + +#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino) + +The `write()` method allows you to write a single byte of data to the EEPROM. +Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`). + +This function does not return any value. + +#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino) + +This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells. + +This function does not return any value. + +#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino) + +This function will retrieve any object from the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino) + +This function will write any object to the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write. + +This function uses the _update_ method to write its data, and therefore only rewrites changed cells. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino) + +This operator allows using the identifier `EEPROM` like an array. +EEPROM cells can be read _and_ **_written_** directly using this method. + +This operator returns a reference to the EEPROM cell. + +```c++ +unsigned char val; + +//Read first EEPROM cell. +val = EEPROM[ 0 ]; + +//Write first EEPROM cell. +EEPROM[ 0 ] = val; + +//Compare contents +if( val == EEPROM[ 0 ] ){ + //Do something... +} +``` + +#### **`EEPROM.length()`** + +This function returns an `unsigned int` containing the number of cells in the EEPROM. + +--- + +### **Advanced features** + +This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`. + +#### **`EERef` class** + +This object references an EEPROM cell. +Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. +This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. + +```C++ +EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell. + +ref = 4; //write to EEPROM cell. + +unsigned char val = ref; //Read referenced cell. +``` + +#### **`EEPtr` class** + +This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects. +Just like a normal pointer type, this type can be dereferenced and repositioned using +increment/decrement operators. + +```C++ +EEPtr ptr = 10; //Create a pointer to 11th cell. + +*ptr = 4; //dereference and write to EEPROM cell. + +unsigned char val = *ptr; //dereference and read. + +ptr++; //Move to next EEPROM cell. +``` + +#### **`EEPROM.begin()`** + +This function returns an `EEPtr` pointing to the first cell in the EEPROM. +This is useful for STL objects, custom iteration and C++11 style ranged for loops. + +#### **`EEPROM.end()`** + +This function returns an `EEPtr` pointing at the location after the last EEPROM cell. +Used with `begin()` to provide custom iteration. + +**Note:** The `EEPtr` returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell. diff --git a/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino b/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 00000000..8b5121c8 --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,39 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0. + * Please see eeprom_iteration for a more in depth + * look at how to traverse the EEPROM. + * + * This example code is in the public domain. + */ + +#include + +void setup() { + // initialize the LED pin as an output. + pinMode(13, OUTPUT); + + /*** + Iterate through each byte of the EEPROM storage. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + + for (int i = 0 ; i < EEPROM.length() ; i++) { + EEPROM.write(i, 0); + } + + // turn the LED on when we're done + digitalWrite(13, HIGH); +} + +void loop() { + /** Empty loop. **/ +} diff --git a/libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino b/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino similarity index 88% rename from libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino rename to libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino index 84294810..c6db85c3 100644 --- a/libraries/CurieEEPROM/examples/eeprom_crc/eeprom_crc.ino +++ b/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino @@ -5,11 +5,10 @@ A CRC is a simple way of checking whether data has changed or become corrupted. This example calculates a CRC value directly on the EEPROM values. The purpose of this example is to highlight how the EEPROM object can be used just like an array. - - 01/05/2016 - Modified for Arduino 101 - Dino Tinitigan ***/ -#include +#include +#include void setup() { @@ -44,10 +43,10 @@ unsigned long eeprom_crc(void) { unsigned long crc = ~0L; - for (int index = 0 ; index < EEPROM.length(); ++index) { + for (int index = 0 ; index < EEPROM.length() ; ++index) { crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4); crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4); crc = ~crc; } return crc; -} \ No newline at end of file +} diff --git a/libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino b/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino similarity index 94% rename from libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino rename to libraries/EEPROM/examples/eeprom_get/eeprom_get.ino index 2fd3e072..a07cee7c 100644 --- a/libraries/CurieEEPROM/examples/eeprom_get/eeprom_get.ino +++ b/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino @@ -15,7 +15,7 @@ Released under MIT licence. ***/ -#include +#include void setup() { @@ -52,7 +52,7 @@ struct MyObject { }; void secondTest() { - int eeAddress = 1; //Move address to the next byte after float 'f'. + int eeAddress = sizeof(float); //Move address to the next byte after float 'f'. MyObject customVar; //Variable to store custom object read from EEPROM. EEPROM.get(eeAddress, customVar); diff --git a/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino b/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino new file mode 100644 index 00000000..3673b472 --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino @@ -0,0 +1,57 @@ +/*** + eeprom_iteration example. + + A set of example snippets highlighting the + simplest methods for traversing the EEPROM. + + Running this sketch is not necessary, this is + simply highlighting certain programming methods. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + /*** + Iterate the EEPROM using a for loop. + ***/ + + for (int index = 0 ; index < EEPROM.length() ; index++) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + } + + /*** + Iterate the EEPROM using a while loop. + ***/ + + int index = 0; + + while (index < EEPROM.length()) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + index++; + } + + /*** + Iterate the EEPROM using a do-while loop. + ***/ + + int idx = 0; //Used 'idx' to avoid name conflict with 'index' above. + + do { + + //Add one to each cell in the EEPROM + EEPROM[ idx ] += 1; + idx++; + } while (idx < EEPROM.length()); + + +} //End of setup function. + +void loop() {} \ No newline at end of file diff --git a/libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino b/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino similarity index 92% rename from libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino rename to libraries/EEPROM/examples/eeprom_put/eeprom_put.ino index 4435e7c4..c1ba0a57 100644 --- a/libraries/CurieEEPROM/examples/eeprom_put/eeprom_put.ino +++ b/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino @@ -14,7 +14,7 @@ Released under MIT licence. ***/ -#include +#include struct MyObject { float field1; @@ -47,7 +47,8 @@ void setup() { "Working!" }; - eeAddress++; + eeAddress += sizeof(float); //Move address to the next byte after float 'f'. + EEPROM.put(eeAddress, customVar); Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!"); } diff --git a/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino b/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 00000000..a8a3510d --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,56 @@ +/* + * EEPROM Read + * + * Reads the value of each byte of the EEPROM and prints it + * to the computer. + * This example code is in the public domain. + */ + +#include + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +byte value; + +void setup() { + // initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } +} + +void loop() { + // read a byte from the current address of the EEPROM + value = EEPROM.read(address); + + Serial.print(address); + Serial.print("\t"); + Serial.print(value, DEC); + Serial.println(); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(500); +} diff --git a/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino b/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino new file mode 100644 index 00000000..5e3db5b4 --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino @@ -0,0 +1,71 @@ +/*** + EEPROM Update method + + Stores values read from analog input 0 into the EEPROM. + These values will stay in the EEPROM when the board is + turned off and may be retrieved later by another sketch. + + If a value has not changed in the EEPROM, it is not overwritten + which would reduce the life span of the EEPROM unnecessarily. + + Released using MIT licence. + ***/ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int address = 0; + +void setup() { + /** EMpty setup **/ +} + +void loop() { + /*** + need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + int val = analogRead(0) / 4; + + /*** + Update the particular EEPROM cell. + these values will remain there when the board is + turned off. + ***/ + EEPROM.update(address, val); + + /*** + The function EEPROM.update(address, val) is equivalent to the following: + + if( EEPROM.read(address) != val ){ + EEPROM.write(address, val); + } + ***/ + + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(100); +} diff --git a/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino b/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 00000000..f9bea641 --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,60 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + */ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int addr = 0; + +void setup() { + /** Empty setup. **/ +} + +void loop() { + /*** + Need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + + int val = analogRead(0) / 4; + + /*** + Write the value to the appropriate byte of the EEPROM. + these values will remain there when the board is + turned off. + ***/ + + EEPROM.write(addr, val); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + addr = addr + 1; + if (addr == EEPROM.length()) { + addr = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++addr &= EEPROM.length() - 1; + ***/ + + + delay(100); +} diff --git a/libraries/CurieEEPROM/keywords.txt b/libraries/EEPROM/keywords.txt similarity index 70% rename from libraries/CurieEEPROM/keywords.txt rename to libraries/EEPROM/keywords.txt index 2225b9ce..2cabc0b0 100644 --- a/libraries/CurieEEPROM/keywords.txt +++ b/libraries/EEPROM/keywords.txt @@ -6,23 +6,16 @@ # Datatypes (KEYWORD1) ####################################### -CurieEEPROM KEYWORD1 -EEPROM KEYWORD1 +EEPROM KEYWORD1 +EERef KEYWORD1 +EEPtr KEYWORD2 ####################################### # Methods and Functions (KEYWORD2) ####################################### -write KEYWORD2 -write8 KEYWORD2 update KEYWORD2 -update8 KEYWORD2 -clear KEYWORD2 -begin KEYWORD2 -end KEYWORD2 -length KEYWORD2 -put KEYWORD2 -get KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/libraries/EEPROM/library.properties b/libraries/EEPROM/library.properties new file mode 100644 index 00000000..325290cf --- /dev/null +++ b/libraries/EEPROM/library.properties @@ -0,0 +1,10 @@ +name=EEPROM +version=2.0 +author=Arduino, Christopher Andrews, Intel +maintainer=Arduino +sentence=Enables reading and writing to the permanent board storage. +paragraph=This library allows to read and write data in a memory type, the EEPROM, that keeps its content also when the board is powered off. The amount of EEPROM available depends on the microcontroller type. +category=Data Storage +url=http://www.arduino.cc/en/Reference/EEPROM +architectures=arc32 + diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h new file mode 100644 index 00000000..c52737c7 --- /dev/null +++ b/libraries/EEPROM/src/EEPROM.h @@ -0,0 +1,256 @@ +/* + EEPROM.h - EEPROM library + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + Curie porting by Intel and Arduino LLC - 2016 + 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 St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#define ROM_WR_CTRL 0xb0100004 +#define ROM_WR_DATA 0xb0100008 +#define FLASH_STTS 0xb0000014 +#define EEPROM_ADDR 0xfffff000 +#define EEPROM_OFFSET 0x00001000 +#define CTRL_REG 0xb0000018 + +#define EEPROM_SIZE 2048 //EEPROM size in bytes + + +#include +#include "Arduino.h" + +/* Curie specific implementation of "atomic" read8 and write8 on OTP flash storage */ + +void CurieClear() +{ + //erase the 2k bytes of the eeprom section inside the otp area + *(uint32_t*)(ROM_WR_CTRL) = 0x4002; + //wait for erase to be complete + #if 0 + while(((*(uint32_t*)FLASH_STTS) & 0x01) == 0) { // TODO: wait for FLASH_STTS.ER_DONE to be set to 1 + delay(1); + } + #endif + delay(5); +} + +void CurieRestoreMemory(uint32_t* buffer, uint32_t size) +{ + uint32_t rom_wr_ctrl = 0; + uint32_t address; + + for (uint32_t i=0; i 0x7FF)) + { + return 0; + } + int offset = address%4; + uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); + value = (value >> ((3-offset)*8)) & 0xFF; + return (uint8_t)value; +} + +uint32_t CurieRead32(uint32_t address) +{ + if((address > 0x7FF)) + { + return 0; + } + uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); + return value; +} + +void CurieWrite8(uint32_t address, uint8_t data) +{ + //make sure address is valid + if((address > 0x7FF)) + { + return; + } + + uint8_t currentValue = CurieRead8(address); + //only do something if value is different from what is currently stored + if(currentValue==data) + { + return; + } + + uint32_t currentDword = CurieRead32(address); + + int offset = address%4; + + uint32_t data32 = (currentDword & ~(uint32_t)(0xFF << ((3-offset)*8))); + data32 = data32 | (data << ((3-offset)*8)); + + if (currentValue != 0xFF) { + uint32_t dump[EEPROM_SIZE/4]; + memcpy(dump, (uint32_t *)EEPROM_ADDR, EEPROM_SIZE); + dump[(address >> 2)] = data32; + CurieClear(); + CurieRestoreMemory((uint32_t *)dump, EEPROM_SIZE/sizeof(uint32_t)); + return; + } + + uint32_t rom_wr_ctrl = 0; + + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = data32; + address = ((address >> 2) << 2) + EEPROM_OFFSET; + rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + + delay(3); //give it enough time to finish writing +} + +/*** + EERef class. + + This object references an EEPROM cell. + Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. + This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. +***/ + +struct EERef{ + + EERef( const int index ) + : index( index ) {} + + //Access/read members. + uint8_t operator*() const { return CurieRead8( (uint32_t) index ); } + operator const uint8_t() const { return **this; } + + //Assignment/write members. + EERef &operator=( const EERef &ref ) { return *this = *ref; } + EERef &operator=( uint8_t in ) { return CurieWrite8( (uint32_t) index, in ), *this; } + EERef &operator +=( uint8_t in ) { return *this = **this + in; } + EERef &operator -=( uint8_t in ) { return *this = **this - in; } + EERef &operator *=( uint8_t in ) { return *this = **this * in; } + EERef &operator /=( uint8_t in ) { return *this = **this / in; } + EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } + EERef &operator %=( uint8_t in ) { return *this = **this % in; } + EERef &operator &=( uint8_t in ) { return *this = **this & in; } + EERef &operator |=( uint8_t in ) { return *this = **this | in; } + EERef &operator <<=( uint8_t in ) { return *this = **this << in; } + EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } + + EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } + + /** Prefix increment/decrement **/ + EERef& operator++() { return *this += 1; } + EERef& operator--() { return *this -= 1; } + + /** Postfix increment/decrement **/ + uint8_t operator++ (int){ + uint8_t ret = **this; + return ++(*this), ret; + } + + uint8_t operator-- (int){ + uint8_t ret = **this; + return --(*this), ret; + } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPtr class. + + This object is a bidirectional pointer to EEPROM cells represented by EERef objects. + Just like a normal pointer type, this can be dereferenced and repositioned using + increment/decrement operators. +***/ + +struct EEPtr{ + + EEPtr( const int index ) + : index( index ) {} + + operator const int() const { return index; } + EEPtr &operator=( int in ) { return index = in, *this; } + + //Iterator functionality. + bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } + EERef operator*() { return index; } + + /** Prefix & Postfix increment/decrement **/ + EEPtr& operator++() { return ++index, *this; } + EEPtr& operator--() { return --index, *this; } + EEPtr operator++ (int) { return index++; } + EEPtr operator-- (int) { return index--; } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPROMClass class. + + This object represents the entire EEPROM space. + It wraps the functionality of EEPtr and EERef into a basic interface. + This class is also 100% backwards compatible with earlier Arduino core releases. +***/ + +struct EEPROMClass{ + + //Basic user access methods. + EERef operator[]( const int idx ) { return idx; } + uint8_t read( int idx ) { return EERef( idx ); } + void write( int idx, uint8_t val ) { (EERef( idx )) = val; } + void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } + + //STL and C++11 iteration capability. + EEPtr begin() { return 0x00; } + EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. + uint16_t length() { return EEPROM_SIZE; } + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template< typename T > T &get( int idx, T &t ){ + EEPtr e = idx; + uint8_t *ptr = (uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; + return t; + } + + template< typename T > const T &put( int idx, const T &t ){ + EEPtr e = idx; + const uint8_t *ptr = (const uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); + return t; + } +}; + +static EEPROMClass EEPROM; +#endif \ No newline at end of file From 77d908688e799557fa6e582fbd885c825aaa07c6 Mon Sep 17 00:00:00 2001 From: Calvin Sangbin Park Date: Mon, 19 Sep 2016 16:48:28 -0700 Subject: [PATCH 097/222] Rebuilt libarc --- .gitignore | 2 +- variants/arduino_101/libarc32drv_arduino101.a | Bin 0 -> 536328 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 variants/arduino_101/libarc32drv_arduino101.a diff --git a/.gitignore b/.gitignore index 908c9e9c..4aac30cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ *.o -*.a +/system/libarc32_arduino101/libarc32drv_arduino101.a *.map *.elf *.swp diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a new file mode 100644 index 0000000000000000000000000000000000000000..ff809d808f9a43ca3dbce2f609201934bd3a88db GIT binary patch literal 536328 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

P+-1C@&?AOj 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