Show2Me control FW, initial shared version
Dependencies: SDFileSystem_HelloWorld mbed FATFileSystem
Fork of 000_GEO_SHOW2ME_OK_F411RE by
Revision 2:bbc3e860fa3d, committed 2018-02-13
- Comitter:
- walter76
- Date:
- Tue Feb 13 08:22:23 2018 +0000
- Parent:
- 1:e4d7342be507
- Commit message:
- Preliminary version used to test all HW sections
Changed in this revision
diff -r e4d7342be507 -r bbc3e860fa3d 000_GEO_CONTROL_OK_F411RE.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/000_GEO_CONTROL_OK_F411RE.lib Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/mbed_official/code/SDFileSystem_HelloWorld/#e4d7342be507
diff -r e4d7342be507 -r bbc3e860fa3d QEI/.hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QEI/.hgignore Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,19 @@ +syntax: regexp +\.hgignore$ +\.git$ +\.svn$ +\.orig$ +\.msub$ +\.meta$ +\.ctags +\.uvproj$ +\.uvopt$ +\.project$ +\.cproject$ +\.launch$ +\.project$ +\.cproject$ +\.launch$ +Makefile$ +\.ewp$ +\.eww$ \ No newline at end of file
diff -r e4d7342be507 -r bbc3e860fa3d QEI/QEI.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QEI/QEI.cpp Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,289 @@ +/** + * @author Aaron Berk + * + * @section LICENSE + * + * Copyright (c) 2010 ARM Limited + * + * 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. + * + * @section DESCRIPTION + * + * Quadrature Encoder Interface. + * + * A quadrature encoder consists of two code tracks on a disc which are 90 + * degrees out of phase. It can be used to determine how far a wheel has + * rotated, relative to a known starting position. + * + * Only one code track changes at a time leading to a more robust system than + * a single track, because any jitter around any edge won't cause a state + * change as the other track will remain constant. + * + * Encoders can be a homebrew affair, consisting of infrared emitters/receivers + * and paper code tracks consisting of alternating black and white sections; + * alternatively, complete disk and PCB emitter/receiver encoder systems can + * be bought, but the interface, regardless of implementation is the same. + * + * +-----+ +-----+ +-----+ + * Channel A | ^ | | | | | + * ---+ ^ +-----+ +-----+ +----- + * ^ ^ + * ^ +-----+ +-----+ +-----+ + * Channel B ^ | | | | | | + * ------+ +-----+ +-----+ +----- + * ^ ^ + * ^ ^ + * 90deg + * + * The interface uses X2 encoding by default which calculates the pulse count + * based on reading the current state after each rising and falling edge of + * channel A. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 ... + * + * This interface can also use X4 encoding which calculates the pulse count + * based on reading the current state after each rising and falling edge of + * either channel. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 6 7 8 9 ... + * + * It defaults + * + * An optional index channel can be used which determines when a full + * revolution has occured. + * + * If a 4 pules per revolution encoder was used, with X4 encoding, + * the following would be observed. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ +--+ ^ ^ +--+ ^ + * ^ ^ ^ | | ^ ^ | | ^ + * Index ------------+ +--------+ +----------- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 6 7 8 9 ... + * Rev. count 0 1 2 + * + * Rotational position in degrees can be calculated by: + * + * (pulse count / X * N) * 360 + * + * Where X is the encoding type [e.g. X4 encoding => X=4], and N is the number + * of pulses per revolution. + * + * Linear position can be calculated by: + * + * (pulse count / X * N) * (1 / PPI) + * + * Where X is encoding type [e.g. X4 encoding => X=44], N is the number of + * pulses per revolution, and PPI is pulses per inch, or the equivalent for + * any other unit of displacement. PPI can be calculated by taking the + * circumference of the wheel or encoder disk and dividing it by the number + * of pulses per revolution. + */ + +/** + * Includes + */ +#include "QEI.h" + +QEI::QEI(PinName channelA, + PinName channelB, + PinName index, + int pulsesPerRev, + Encoding encoding) : channelA_(channelA), channelB_(channelB), + index_(index) { + + pulses_ = 0; + revolutions_ = 0; + pulsesPerRev_ = pulsesPerRev; + encoding_ = encoding; + + //Workout what the current state is. + int chanA = channelA_.read(); + int chanB = channelB_.read(); + + //2-bit state. + currState_ = (chanA << 1) | (chanB); + prevState_ = currState_; + + //X2 encoding uses interrupts on only channel A. + //X4 encoding uses interrupts on channel A, + //and on channel B. + channelA_.rise(this, &QEI::encode); + channelA_.fall(this, &QEI::encode); + + //If we're using X4 encoding, then attach interrupts to channel B too. + if (encoding == X4_ENCODING) { + channelB_.rise(this, &QEI::encode); + channelB_.fall(this, &QEI::encode); + } + //Index is optional. + if (index != NC) { + index_.rise(this, &QEI::index); + } + +} + +void QEI::reset(void) { + + pulses_ = 0; + revolutions_ = 0; + +} + +int QEI::getCurrentState(void) { + + return currState_; + +} + +int QEI::getPulses(void) { + + return pulses_; + +} + +int QEI::getRevolutions(void) { + + return revolutions_; + +} + +// +-------------+ +// | X2 Encoding | +// +-------------+ +// +// When observing states two patterns will appear: +// +// Counter clockwise rotation: +// +// 10 -> 01 -> 10 -> 01 -> ... +// +// Clockwise rotation: +// +// 11 -> 00 -> 11 -> 00 -> ... +// +// We consider counter clockwise rotation to be "forward" and +// counter clockwise to be "backward". Therefore pulse count will increase +// during counter clockwise rotation and decrease during clockwise rotation. +// +// +-------------+ +// | X4 Encoding | +// +-------------+ +// +// There are four possible states for a quadrature encoder which correspond to +// 2-bit gray code. +// +// A state change is only valid if of only one bit has changed. +// A state change is invalid if both bits have changed. +// +// Clockwise Rotation -> +// +// 00 01 11 10 00 +// +// <- Counter Clockwise Rotation +// +// If we observe any valid state changes going from left to right, we have +// moved one pulse clockwise [we will consider this "backward" or "negative"]. +// +// If we observe any valid state changes going from right to left we have +// moved one pulse counter clockwise [we will consider this "forward" or +// "positive"]. +// +// We might enter an invalid state for a number of reasons which are hard to +// predict - if this is the case, it is generally safe to ignore it, update +// the state and carry on, with the error correcting itself shortly after. +void QEI::encode(void) { + + int change = 0; + int chanA = channelA_.read(); + int chanB = channelB_.read(); + + //2-bit state. + currState_ = (chanA << 1) | (chanB); + + if (encoding_ == X2_ENCODING) { + + //11->00->11->00 is counter clockwise rotation or "forward". + if ((prevState_ == 0x3 && currState_ == 0x0) || + (prevState_ == 0x0 && currState_ == 0x3)) { + + pulses_++; + + } + //10->01->10->01 is clockwise rotation or "backward". + else if ((prevState_ == 0x2 && currState_ == 0x1) || + (prevState_ == 0x1 && currState_ == 0x2)) { + + pulses_--; + + } + + } else if (encoding_ == X4_ENCODING) { + + //Entered a new valid state. + if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) { + //2 bit state. Right hand bit of prev XOR left hand bit of current + //gives 0 if clockwise rotation and 1 if counter clockwise rotation. + change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1); + + if (change == 0) { + change = -1; + } + + pulses_ -= change; + } + + } + + prevState_ = currState_; + +} + +void QEI::index(void) { + + revolutions_++; + +}
diff -r e4d7342be507 -r bbc3e860fa3d QEI/QEI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QEI/QEI.h Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,244 @@ +/** + * @author Aaron Berk + * + * @section LICENSE + * + * Copyright (c) 2010 ARM Limited + * + * 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. + * + * @section DESCRIPTION + * + * Quadrature Encoder Interface. + * + * A quadrature encoder consists of two code tracks on a disc which are 90 + * degrees out of phase. It can be used to determine how far a wheel has + * rotated, relative to a known starting position. + * + * Only one code track changes at a time leading to a more robust system than + * a single track, because any jitter around any edge won't cause a state + * change as the other track will remain constant. + * + * Encoders can be a homebrew affair, consisting of infrared emitters/receivers + * and paper code tracks consisting of alternating black and white sections; + * alternatively, complete disk and PCB emitter/receiver encoder systems can + * be bought, but the interface, regardless of implementation is the same. + * + * +-----+ +-----+ +-----+ + * Channel A | ^ | | | | | + * ---+ ^ +-----+ +-----+ +----- + * ^ ^ + * ^ +-----+ +-----+ +-----+ + * Channel B ^ | | | | | | + * ------+ +-----+ +-----+ +----- + * ^ ^ + * ^ ^ + * 90deg + * + * The interface uses X2 encoding by default which calculates the pulse count + * based on reading the current state after each rising and falling edge of + * channel A. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 ... + * + * This interface can also use X4 encoding which calculates the pulse count + * based on reading the current state after each rising and falling edge of + * either channel. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 6 7 8 9 ... + * + * It defaults + * + * An optional index channel can be used which determines when a full + * revolution has occured. + * + * If a 4 pules per revolution encoder was used, with X4 encoding, + * the following would be observed. + * + * +-----+ +-----+ +-----+ + * Channel A | | | | | | + * ---+ +-----+ +-----+ +----- + * ^ ^ ^ ^ ^ + * ^ +-----+ ^ +-----+ ^ +-----+ + * Channel B ^ | ^ | ^ | ^ | ^ | | + * ------+ ^ +-----+ ^ +-----+ +-- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * ^ ^ ^ +--+ ^ ^ +--+ ^ + * ^ ^ ^ | | ^ ^ | | ^ + * Index ------------+ +--------+ +----------- + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * Pulse count 0 1 2 3 4 5 6 7 8 9 ... + * Rev. count 0 1 2 + * + * Rotational position in degrees can be calculated by: + * + * (pulse count / X * N) * 360 + * + * Where X is the encoding type [e.g. X4 encoding => X=4], and N is the number + * of pulses per revolution. + * + * Linear position can be calculated by: + * + * (pulse count / X * N) * (1 / PPI) + * + * Where X is encoding type [e.g. X4 encoding => X=44], N is the number of + * pulses per revolution, and PPI is pulses per inch, or the equivalent for + * any other unit of displacement. PPI can be calculated by taking the + * circumference of the wheel or encoder disk and dividing it by the number + * of pulses per revolution. + */ + +#ifndef QEI_H +#define QEI_H + +/** + * Includes + */ +#include "mbed.h" + +/** + * Defines + */ +#define PREV_MASK 0x1 //Mask for the previous state in determining direction +//of rotation. +#define CURR_MASK 0x2 //Mask for the current state in determining direction +//of rotation. +#define INVALID 0x3 //XORing two states where both bits have changed. + +/** + * Quadrature Encoder Interface. + */ +class QEI { + +public: + + typedef enum Encoding { + + X2_ENCODING, + X4_ENCODING + + } Encoding; + + /** + * Constructor. + * + * Reads the current values on channel A and channel B to determine the + * initial state. + * + * Attaches the encode function to the rise/fall interrupt edges of + * channels A and B to perform X4 encoding. + * + * Attaches the index function to the rise interrupt edge of channel index + * (if it is used) to count revolutions. + * + * @param channelA mbed pin for channel A input. + * @param channelB mbed pin for channel B input. + * @param index mbed pin for optional index channel input, + * (pass NC if not needed). + * @param pulsesPerRev Number of pulses in one revolution. + * @param encoding The encoding to use. Uses X2 encoding by default. X2 + * encoding uses interrupts on the rising and falling edges + * of only channel A where as X4 uses them on both + * channels. + */ + QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev, Encoding encoding = X2_ENCODING); + + /** + * Reset the encoder. + * + * Sets the pulses and revolutions count to zero. + */ + void reset(void); + + /** + * Read the state of the encoder. + * + * @return The current state of the encoder as a 2-bit number, where: + * bit 1 = The reading from channel B + * bit 2 = The reading from channel A + */ + int getCurrentState(void); + + /** + * Read the number of pulses recorded by the encoder. + * + * @return Number of pulses which have occured. + */ + int getPulses(void); + + /** + * Read the number of revolutions recorded by the encoder on the index channel. + * + * @return Number of revolutions which have occured on the index channel. + */ + int getRevolutions(void); + +private: + + /** + * Update the pulse count. + * + * Called on every rising/falling edge of channels A/B. + * + * Reads the state of the channels and determines whether a pulse forward + * or backward has occured, updating the count appropriately. + */ + void encode(void); + + /** + * Called on every rising edge of channel index to update revolution + * count by one. + */ + void index(void); + + Encoding encoding_; + + InterruptIn channelA_; + InterruptIn channelB_; + InterruptIn index_; + + int pulsesPerRev_; + int prevState_; + int currState_; + + volatile int pulses_; + volatile int revolutions_; + +}; + +#endif /* QEI_H */
diff -r e4d7342be507 -r bbc3e860fa3d SDFileSystem.lib --- a/SDFileSystem.lib Tue May 16 05:18:55 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/SDFileSystem/#8db0d3b02cec
diff -r e4d7342be507 -r bbc3e860fa3d SDFileSystem/FATFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem/FATFileSystem.lib Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/mbed-official/code/FATFileSystem/#e2ab678eb692
diff -r e4d7342be507 -r bbc3e860fa3d SDFileSystem/SDFileSystem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem/SDFileSystem.cpp Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,498 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * 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. + */ +/* Introduction + * ------------ + * SD and MMC cards support a number of interfaces, but common to them all + * is one based on SPI. This is the one I'm implmenting because it means + * it is much more portable even though not so performant, and we already + * have the mbed SPI Interface! + * + * The main reference I'm using is Chapter 7, "SPI Mode" of: + * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf + * + * SPI Startup + * ----------- + * The SD card powers up in SD mode. The SPI interface mode is selected by + * asserting CS low and sending the reset command (CMD0). The card will + * respond with a (R1) response. + * + * CMD8 is optionally sent to determine the voltage range supported, and + * indirectly determine whether it is a version 1.x SD/non-SD card or + * version 2.x. I'll just ignore this for now. + * + * ACMD41 is repeatedly issued to initialise the card, until "in idle" + * (bit 0) of the R1 response goes to '0', indicating it is initialised. + * + * You should also indicate whether the host supports High Capicity cards, + * and check whether the card is high capacity - i'll also ignore this + * + * SPI Protocol + * ------------ + * The SD SPI protocol is based on transactions made up of 8-bit words, with + * the host starting every bus transaction by asserting the CS signal low. The + * card always responds to commands, data blocks and errors. + * + * The protocol supports a CRC, but by default it is off (except for the + * first reset CMD0, where the CRC can just be pre-calculated, and CMD8) + * I'll leave the CRC off I think! + * + * Standard capacity cards have variable data block sizes, whereas High + * Capacity cards fix the size of data block to 512 bytes. I'll therefore + * just always use the Standard Capacity cards with a block size of 512 bytes. + * This is set with CMD16. + * + * You can read and write single blocks (CMD17, CMD25) or multiple blocks + * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When + * the card gets a read command, it responds with a response token, and then + * a data token or an error. + * + * SPI Command Format + * ------------------ + * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC. + * + * +---------------+------------+------------+-----------+----------+--------------+ + * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 | + * +---------------+------------+------------+-----------+----------+--------------+ + * + * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95) + * + * All Application Specific commands shall be preceded with APP_CMD (CMD55). + * + * SPI Response Format + * ------------------- + * The main response format (R1) is a status byte (normally zero). Key flags: + * idle - 1 if the card is in an idle state/initialising + * cmd - 1 if an illegal command code was detected + * + * +-------------------------------------------------+ + * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle | + * +-------------------------------------------------+ + * + * R1b is the same, except it is followed by a busy signal (zeros) until + * the first non-zero byte when it is ready again. + * + * Data Response Token + * ------------------- + * Every data block written to the card is acknowledged by a byte + * response token + * + * +----------------------+ + * | xxx | 0 | status | 1 | + * +----------------------+ + * 010 - OK! + * 101 - CRC Error + * 110 - Write Error + * + * Single Block Read and Write + * --------------------------- + * + * Block transfers have a byte header, followed by the data, followed + * by a 16-bit CRC. In our case, the data will always be 512 bytes. + * + * +------+---------+---------+- - - -+---------+-----------+----------+ + * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] | + * +------+---------+---------+- - - -+---------+-----------+----------+ + */ +#include "SDFileSystem.h" +#include "mbed_debug.h" + +#define SD_COMMAND_TIMEOUT 5000 + +#define SD_DBG 0 + +SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) : + FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) { + _cs = 1; + + // Set default to 100kHz for initialisation and 1MHz for data transfer + _init_sck = 100000; + _transfer_sck = 1000000; +} + +#define R1_IDLE_STATE (1 << 0) +#define R1_ERASE_RESET (1 << 1) +#define R1_ILLEGAL_COMMAND (1 << 2) +#define R1_COM_CRC_ERROR (1 << 3) +#define R1_ERASE_SEQUENCE_ERROR (1 << 4) +#define R1_ADDRESS_ERROR (1 << 5) +#define R1_PARAMETER_ERROR (1 << 6) + +// Types +// - v1.x Standard Capacity +// - v2.x Standard Capacity +// - v2.x High Capacity +// - Not recognised as an SD Card +#define SDCARD_FAIL 0 +#define SDCARD_V1 1 +#define SDCARD_V2 2 +#define SDCARD_V2HC 3 + +int SDFileSystem::initialise_card() { + // Set to SCK for initialisation, and clock card with cs = 1 + _spi.frequency(_init_sck); + _cs = 1; + for (int i = 0; i < 16; i++) { + _spi.write(0xFF); + } + + // send CMD0, should return with all zeros except IDLE STATE set (bit 0) + if (_cmd(0, 0) != R1_IDLE_STATE) { + debug("No disk, or could not put SD card in to SPI idle state\n"); + return SDCARD_FAIL; + } + + // send CMD8 to determine whther it is ver 2.x + int r = _cmd8(); + if (r == R1_IDLE_STATE) { + return initialise_card_v2(); + } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) { + return initialise_card_v1(); + } else { + debug("Not in idle state after sending CMD8 (not an SD card?)\n"); + return SDCARD_FAIL; + } +} + +int SDFileSystem::initialise_card_v1() { + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + _cmd(55, 0); + if (_cmd(41, 0) == 0) { + cdv = 512; + debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r"); + return SDCARD_V1; + } + } + + debug("Timeout waiting for v1.x card\n"); + return SDCARD_FAIL; +} + +int SDFileSystem::initialise_card_v2() { + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + wait_ms(50); + _cmd58(); + _cmd(55, 0); + if (_cmd(41, 0x40000000) == 0) { + _cmd58(); + debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r"); + cdv = 1; + return SDCARD_V2; + } + } + + debug("Timeout waiting for v2.x card\n"); + return SDCARD_FAIL; +} + +int SDFileSystem::disk_initialize() { + _is_initialized = initialise_card(); + if (_is_initialized == 0) { + debug("Fail to initialize card\n"); + return 1; + } + debug_if(SD_DBG, "init card = %d\n", _is_initialized); + _sectors = _sd_sectors(); + + // Set block length to 512 (CMD16) + if (_cmd(16, 512) != 0) { + debug("Set 512-byte block timed out\n"); + return 1; + } + + // Set SCK for data transfer + _spi.frequency(_transfer_sck); + return 0; +} + +int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) { + if (!_is_initialized) { + return -1; + } + + for (uint32_t b = block_number; b < block_number + count; b++) { + // set write address for single block (CMD24) + if (_cmd(24, b * cdv) != 0) { + return 1; + } + + // send the data block + _write(buffer, 512); + buffer += 512; + } + + return 0; +} + +int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) { + if (!_is_initialized) { + return -1; + } + + for (uint32_t b = block_number; b < block_number + count; b++) { + // set read address for single block (CMD17) + if (_cmd(17, b * cdv) != 0) { + return 1; + } + + // receive the data + _read(buffer, 512); + buffer += 512; + } + + return 0; +} + +int SDFileSystem::disk_status() { + // FATFileSystem::disk_status() returns 0 when initialized + if (_is_initialized) { + return 0; + } else { + return 1; + } +} + +int SDFileSystem::disk_sync() { return 0; } +uint32_t SDFileSystem::disk_sectors() { return _sectors; } + + +// PRIVATE FUNCTIONS +int SDFileSystem::_cmd(int cmd, int arg) { + _cs = 0; + + // send a command + _spi.write(0x40 | cmd); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + _cs = 1; + _spi.write(0xFF); + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} +int SDFileSystem::_cmdx(int cmd, int arg) { + _cs = 0; + + // send a command + _spi.write(0x40 | cmd); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + + +int SDFileSystem::_cmd58() { + _cs = 0; + int arg = 0; + + // send a command + _spi.write(0x40 | 58); + _spi.write(arg >> 24); + _spi.write(arg >> 16); + _spi.write(arg >> 8); + _spi.write(arg >> 0); + _spi.write(0x95); + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = _spi.write(0xFF); + if (!(response & 0x80)) { + int ocr = _spi.write(0xFF) << 24; + ocr |= _spi.write(0xFF) << 16; + ocr |= _spi.write(0xFF) << 8; + ocr |= _spi.write(0xFF) << 0; + _cs = 1; + _spi.write(0xFF); + return response; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + +int SDFileSystem::_cmd8() { + _cs = 0; + + // send a command + _spi.write(0x40 | 8); // CMD8 + _spi.write(0x00); // reserved + _spi.write(0x00); // reserved + _spi.write(0x01); // 3.3v + _spi.write(0xAA); // check pattern + _spi.write(0x87); // crc + + // wait for the repsonse (response[7] == 0) + for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) { + char response[5]; + response[0] = _spi.write(0xFF); + if (!(response[0] & 0x80)) { + for (int j = 1; j < 5; j++) { + response[i] = _spi.write(0xFF); + } + _cs = 1; + _spi.write(0xFF); + return response[0]; + } + } + _cs = 1; + _spi.write(0xFF); + return -1; // timeout +} + +int SDFileSystem::_read(uint8_t *buffer, uint32_t length) { + _cs = 0; + + // read until start byte (0xFF) + while (_spi.write(0xFF) != 0xFE); + + // read data + for (uint32_t i = 0; i < length; i++) { + buffer[i] = _spi.write(0xFF); + } + _spi.write(0xFF); // checksum + _spi.write(0xFF); + + _cs = 1; + _spi.write(0xFF); + return 0; +} + +int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) { + _cs = 0; + + // indicate start of block + _spi.write(0xFE); + + // write the data + for (uint32_t i = 0; i < length; i++) { + _spi.write(buffer[i]); + } + + // write the checksum + _spi.write(0xFF); + _spi.write(0xFF); + + // check the response token + if ((_spi.write(0xFF) & 0x1F) != 0x05) { + _cs = 1; + _spi.write(0xFF); + return 1; + } + + // wait for write to finish + while (_spi.write(0xFF) == 0); + + _cs = 1; + _spi.write(0xFF); + return 0; +} + +static uint32_t ext_bits(unsigned char *data, int msb, int lsb) { + uint32_t bits = 0; + uint32_t size = 1 + msb - lsb; + for (uint32_t i = 0; i < size; i++) { + uint32_t position = lsb + i; + uint32_t byte = 15 - (position >> 3); + uint32_t bit = position & 0x7; + uint32_t value = (data[byte] >> bit) & 1; + bits |= value << i; + } + return bits; +} + +uint32_t SDFileSystem::_sd_sectors() { + uint32_t c_size, c_size_mult, read_bl_len; + uint32_t block_len, mult, blocknr, capacity; + uint32_t hc_c_size; + uint32_t blocks; + + // CMD9, Response R2 (R1 byte + 16-byte block read) + if (_cmdx(9, 0) != 0) { + debug("Didn't get a response from the disk\n"); + return 0; + } + + uint8_t csd[16]; + if (_read(csd, 16) != 0) { + debug("Couldn't read csd response from disk\n"); + return 0; + } + + // csd_structure : csd[127:126] + // c_size : csd[73:62] + // c_size_mult : csd[49:47] + // read_bl_len : csd[83:80] - the *maximum* read block length + + int csd_structure = ext_bits(csd, 127, 126); + + switch (csd_structure) { + case 0: + cdv = 512; + c_size = ext_bits(csd, 73, 62); + c_size_mult = ext_bits(csd, 49, 47); + read_bl_len = ext_bits(csd, 83, 80); + + block_len = 1 << read_bl_len; + mult = 1 << (c_size_mult + 2); + blocknr = (c_size + 1) * mult; + capacity = blocknr * block_len; + blocks = capacity / 512; + debug_if(SD_DBG, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks); + break; + + case 1: + cdv = 1; + hc_c_size = ext_bits(csd, 63, 48); + blocks = (hc_c_size+1)*1024; + debug_if(SD_DBG, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks); + break; + + default: + debug("CSD struct unsupported\r\n"); + return 0; + }; + return blocks; +} \ No newline at end of file
diff -r e4d7342be507 -r bbc3e860fa3d SDFileSystem/SDFileSystem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem/SDFileSystem.h Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,89 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2012 ARM Limited + * + * 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. + */ +#ifndef MBED_SDFILESYSTEM_H +#define MBED_SDFILESYSTEM_H + +#include "mbed.h" +#include "FATFileSystem.h" +#include <stdint.h> + +/** Access the filesystem on an SD Card using SPI + * + * @code + * #include "mbed.h" + * #include "SDFileSystem.h" + * + * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs + * + * int main() { + * FILE *fp = fopen("/sd/myfile.txt", "w"); + * fprintf(fp, "Hello World!\n"); + * fclose(fp); + * } + */ +class SDFileSystem : public FATFileSystem { +public: + + /** Create the File System for accessing an SD Card using SPI + * + * @param mosi SPI mosi pin connected to SD Card + * @param miso SPI miso pin conencted to SD Card + * @param sclk SPI sclk pin connected to SD Card + * @param cs DigitalOut pin used as SD Card chip select + * @param name The name used to access the virtual filesystem + */ + SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name); + virtual int disk_initialize(); + virtual int disk_status(); + virtual int disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count); + virtual int disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count); + virtual int disk_sync(); + virtual uint32_t disk_sectors(); + +protected: + + int _cmd(int cmd, int arg); + int _cmdx(int cmd, int arg); + int _cmd8(); + int _cmd58(); + int initialise_card(); + int initialise_card_v1(); + int initialise_card_v2(); + + int _read(uint8_t * buffer, uint32_t length); + int _write(const uint8_t *buffer, uint32_t length); + uint32_t _sd_sectors(); + uint32_t _sectors; + + void set_init_sck(uint32_t sck) { _init_sck = sck; } + // Note: The highest SPI clock rate is 20 MHz for MMC and 25 MHz for SD + void set_transfer_sck(uint32_t sck) { _transfer_sck = sck; } + uint32_t _init_sck; + uint32_t _transfer_sck; + + SPI _spi; + DigitalOut _cs; + int cdv; + int _is_initialized; +}; + +#endif \ No newline at end of file
diff -r e4d7342be507 -r bbc3e860fa3d ST7565_LCD/ST7565_LCD.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ST7565_LCD/ST7565_LCD.cpp Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,445 @@ + + +#include "mbed.h" +#include "ST7565_LCD.h" +#include "font_5x7.h" + +unsigned int lcd_orientation, lcd_width, lcd_height; +unsigned int p_size, p_x, p_y, p_bg, p_fg; + +//extern const unsigned short font_PGM[]; + +int pagemap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; +/* +// CAUTION HIGH VOLTAGE +unsigned int buffer[128*64/8] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x80, 0xE0, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, +0xF8, 0x0C, 0x04, 0x04, 0x04, 0x0C, 0x08, 0x00, 0x80, 0xF0, 0x7C, 0x0C, 0x7C, 0xF0, 0x80, 0x00, +0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x04, 0x04, +0x04, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0xF0, 0xF8, 0x0C, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, +0xFC, 0xFC, 0x38, 0xE0, 0x80, 0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF0, 0xFC, 0xFF, +0xFF, 0x3F, 0x0F, 0x07, 0x01, 0x00, 0x01, 0x07, 0x0F, 0x3F, 0xFF, 0xFE, 0xFC, 0xF0, 0xC0, 0x80, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +0x07, 0x0C, 0x08, 0x08, 0x08, 0x0C, 0x04, 0x0C, 0x0F, 0x03, 0x02, 0x02, 0x02, 0x03, 0x0F, 0x0C, +0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, +0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x08, 0x08, 0x0C, 0x07, 0x03, 0x00, 0x00, +0x0F, 0x0F, 0x00, 0x00, 0x03, 0x0F, 0x0F, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF8, 0xFE, 0xFF, 0x7F, 0x1F, 0x07, 0x01, +0x00, 0x80, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x00, 0x00, 0x01, 0x07, 0x1F, 0x3F, 0xFF, +0xFE, 0xF8, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xFF, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFE, 0x03, +0x01, 0x21, 0x21, 0xE3, 0xE2, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xC0, 0xE0, 0xF8, 0xFE, 0xFF, 0x7F, 0x1F, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, +0xFC, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x07, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, +0x03, 0x07, 0x1F, 0x7F, 0xFF, 0xFE, 0xF8, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0xC0, 0x40, 0x40, +0xC3, 0x83, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0x00, 0x00, 0x03, 0x03, 0x00, 0x40, 0x40, 0x41, 0xC3, +0xC2, 0x42, 0x42, 0x43, 0x01, 0x00, 0x00, 0xC3, 0xC3, 0xC0, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, +0xC0, 0x40, 0x40, 0x40, 0xC0, 0x80, 0x00, 0x00, 0xC0, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF8, +0xFC, 0xFF, 0x7F, 0x3F, 0x0F, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFC, 0x7F, +0x7F, 0x3F, 0x3F, 0x1F, 0x1C, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x7F, 0xFF, 0xFC, 0xF8, 0xE0, 0x80, 0x00, 0x00, +0x00, 0x00, 0x07, 0x3F, 0xF8, 0xC0, 0xF8, 0x3F, 0x07, 0x00, 0x00, 0x3F, 0x7F, 0xC0, 0x80, 0x80, +0xC0, 0x7F, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, +0xFF, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0x3F, 0x27, 0x20, 0x27, 0x3F, 0xF8, 0xC0, 0x00, 0x3F, 0x7F, +0xC0, 0x80, 0x88, 0x88, 0xF8, 0x78, 0x00, 0x00, 0xFF, 0xFF, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0xFC, 0xFE, 0xFF, 0x3F, 0x1F, +0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x80, 0x80, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x0F, 0x3F, 0x7F, 0xFF, 0xFC, +0xF0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xF8, 0xFE, 0xFF, 0x7F, 0x1F, 0x07, 0x03, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x0F, 0xFF, 0xFF, 0x3F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, +0x0F, 0x3F, 0xFF, 0xFF, 0xFC, 0xF0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x1E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, +0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, +0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, +0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, +0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +*/ + +// GEO ELECTRONICS 2017 +unsigned int buffer[128*64/8] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xC0, +0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0x30, 0x10, 0x08, 0x08, 0x58, 0x78, +0x30, 0x00, 0x00, 0xC8, 0xF8, 0xB8, 0xC8, 0xC8, 0x08, 0x18, 0x18, 0x08, 0xC0, 0xE0, 0x30, 0x10, +0x08, 0x08, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0xF8, 0x78, 0x3C, 0x1E, 0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1F, +0x9F, 0xDF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xE0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x10, 0x10, 0x19, 0x0D, 0x0F, 0x03, 0x11, +0x10, 0x9C, 0x9F, 0x93, 0x90, 0x11, 0x19, 0x08, 0x00, 0x00, 0x00, 0x0F, 0x1B, 0x10, 0x10, 0x08, +0x0C, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0x7F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0xE0, 0xE0, 0xF8, 0xFC, 0x7E, 0xDE, 0xE0, +0xF7, 0xFF, 0xFF, 0xFF, 0xFD, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF8, +0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0xB8, 0x2C, 0x2C, 0xAC, 0x38, 0x00, 0xC0, +0xF0, 0x3C, 0x0F, 0xC3, 0xF0, 0xB8, 0x2C, 0x2C, 0xAC, 0x38, 0x00, 0xC0, 0xF0, 0xB8, 0x0C, 0x0C, +0x84, 0x0C, 0xC0, 0xF4, 0x3C, 0x0F, 0x84, 0x04, 0x00, 0xC4, 0xFC, 0x38, 0x0C, 0x04, 0xEC, 0xF0, +0x98, 0x0C, 0x84, 0xCC, 0x78, 0x00, 0x80, 0xF4, 0x3C, 0x0C, 0xC4, 0x3C, 0x1C, 0x00, 0xC0, 0xF4, +0x3C, 0x0C, 0xC0, 0xF0, 0xB8, 0x08, 0x0C, 0x84, 0x0C, 0x80, 0xB8, 0x3C, 0xE4, 0xCC, 0x08, 0x00, +0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xE3, 0x47, 0x1F, +0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x81, 0xC6, 0xEF, 0xF7, +0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, +0x3F, 0x1F, 0x1F, 0xFC, 0xF0, 0xE0, 0xC0, 0x80, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, +0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, +0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, +0x06, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0x80, 0x00, 0x41, 0xE1, 0xF3, 0xFF, 0xFF, 0xFF, 0xFE, +0xFE, 0xFE, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x06, 0x1F, 0x3F, 0x7F, 0x7F, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFD, 0x0D, 0x04, 0x00, +0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1E, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, +0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1F, 0x7C, 0xE0, 0x80, 0x01, 0x03, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x77, 0x7B, 0x7D, 0x3E, 0x00, 0x80, +0xE0, 0x78, 0x3F, 0x0F, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0xC7, 0xEE, 0xFF, 0xFF, 0xFF, +0xFF, 0xE3, 0xC1, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x03, 0x83, 0x83, 0xC3, 0xC3, 0xE1, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, +0xF1, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, +0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x1F, 0x3F, 0x7E, 0xFE, 0xFE, 0x7E, 0x3E, 0x1E, +0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, +0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +extern const unsigned short font_PGM[]; + + +DigitalOut LCD_RST (D9); // D7=PA8--> LCD Reset +DigitalOut LCD_CS (D10); // D10=PB6--> LCD Chip-Select +DigitalOut LCD_SDI (D11); // D11=PA7--> LCD Serial Data In +DigitalOut LCD_A0 (D12); // D12=PA6--> LCD A0 +DigitalOut LCD_CLK (D13); // D13=PA5--> LCD Serial Clock + + +//============================================================================== + +void Delay_us(int howmany) +{ + int n; + Timer t; + t.start(); + do + { + n=t.read_us(); + } + while (n<= howmany); +} + + +//============================================================================== + + +void SPI_Write(uint8_t data) +{ + + uint8_t mask; + + for(mask=0x80; mask!=0; mask>>=1) + { + LCD_CLK=0; + if(mask & data) + LCD_SDI=1; + + else + LCD_SDI=0; + + LCD_CLK=1; + + } + LCD_CLK=0; + + return; +} + + +//============================================================================== + +void LCD_cmd(uint8_t command) +{ + + LCD_A0=0; + + LCD_CS=0; + SPI_Write(command); + LCD_CS=1; + + return; +} + + +//============================================================================== + +void LCD_data(uint8_t data) +{ + LCD_A0=1; + + LCD_CS=0; + SPI_Write(data); + LCD_CS=1; + + return; +} + + + +//============================================================================== + +void LCD_clear(void) +{ + unsigned int p, c; + + for(p = 0; p < 8; p++) + { + LCD_cmd(CMD_SET_PAGE | p); + for(c = 0; c < 128; c++) + { + LCD_cmd(CMD_SET_COLUMN_LOWER | (c & 0xf)); + LCD_cmd(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf)); + LCD_data(0x0); + } + } + + return; +} + + +//============================================================================== + + +void LCD_reset(void) +{ + + // toggle RST low to reset; CS high + LCD_CS=1; + LCD_RST=0; + wait(0.01); + LCD_RST=1; + + LCD_cmd(CMD_SET_BIAS_7); // LCD bias select + LCD_cmd(CMD_SET_ADC_NORMAL); // ADC select === + LCD_cmd(CMD_SET_COM_REVERSE); // SHL select + LCD_cmd(CMD_SET_DISP_START_LINE); // Initial display line + + LCD_cmd(CMD_SET_POWER_CONTROL | 0x4); // turn on voltage converter (VC=1, VR=0, VF=0) + wait(0.01); + LCD_cmd(CMD_SET_POWER_CONTROL | 0x6); // turn on voltage regulator (VC=1, VR=1, VF=0) + wait(0.01); + LCD_cmd(CMD_SET_POWER_CONTROL | 0x7); // turn on voltage follower (VC=1, VR=1, VF=1) + wait(0.01); + + // set lcd operating voltage (regulator resistor, ref voltage resistor) + LCD_cmd(CMD_SET_RESISTOR_RATIO | 0x6); + + LCD_cmd(CMD_DISPLAY_ON); + LCD_cmd(CMD_SET_ALLPTS_NORMAL); + + // set contrast (leve= 0x09) + LCD_cmd(CMD_SET_VOLUME_FIRST); + LCD_cmd(CMD_SET_VOLUME_SECOND | (0x07 & 0x3f)); + LCD_clear(); + + return; +} + +//============================================================================== + +void LCD_write_buffer(unsigned int *buffer) +{ + unsigned int c, p; + + for(p = 0; p < 8; p++) + { + LCD_cmd(CMD_SET_PAGE | pagemap[p]); + LCD_cmd(CMD_SET_COLUMN_LOWER | (0x0 & 0xf)); + LCD_cmd(CMD_SET_COLUMN_UPPER | ((0x0 >> 4) & 0xf)); + LCD_cmd(CMD_RMW); + LCD_data(0xFF); // X-axis offset + LCD_data(0xFF); + LCD_data(0xFF); + LCD_data(0xFF); + + for(c = 0; c < 128; c++) + { + LCD_data(buffer[(128*p)+c]); + } + } + + return; + +} + + + + +//============================================================================== + +void LCD_setpixel(unsigned int *buff, uint8_t x, uint8_t y, uint8_t color) +{ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)) + return; + + if (color) + buff[x+ (y/8)*128] |= (7-(y%8)); + else + buff[x+ (y/8)*128] &= ~(7-(y%8)); + + return; +} + + +//============================================================================== + +void LCD_clearpixel(unsigned int *buff, uint8_t x, uint8_t y) +{ + if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)) + return; + + buff[x+ (y/8)*128] &= ~(7-(y%8)); + + return; +} + + +//============================================================================== + +void LCD_drawline(unsigned int *buff, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) +{ + uint8_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); + } + + uint8_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int err = dx / 2; + int ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1;} + + for (; x0<x1; x0++) { + if (steep) { + LCD_setpixel(buff, y0, x0, color); + } else { + LCD_setpixel(buff, x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } + + return; +} + + +//============================================================================== + +void LCD_drawchar(unsigned int *buff, uint8_t x, uint8_t line, char c) +{ + uint8_t i; + + for (i =0; i<5; i++ ) + { + buff[x + (line*128) ] = font_PGM[((c-32)*5)+i]; + x++; + } + + return; +} + + +//============================================================================== +// The 128x64 LCD allows 8 rows of 21 chars + +void LCD_drawstring(unsigned int *buff, uint8_t x, uint8_t line, char *c) +{ + unsigned int i=0; + while (c[i] != 0) + { + LCD_drawchar(buff, x, line, c[i]); + i++; + x += 6; // 6 pixels wide + if (x + 6 >= LCD_WIDTH) { + x = 0; // ran out of this line + line++; + } + if (line >= (LCD_HEIGHT/8)) + return; // ran out of space :( + } + + return; +} + + +//============================================================================== + +void Clear_buffer(unsigned int *buff) +{ + unsigned short i; + + for(i=0; i<1024; i++) + buff[i]=0x00; + + return; +} \ No newline at end of file
diff -r e4d7342be507 -r bbc3e860fa3d ST7565_LCD/ST7565_LCD.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ST7565_LCD/ST7565_LCD.h Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,77 @@ +/******************************************************************************* +* File Name : ST7565_LCD.c +* Author : Walter Trovò +* Date First Issued : 20/03/2012 +*******************************************************************************/ + +// ST7565R LCD module driver + +#ifndef __ST7565_LCD_H +#define __ST7565_LCD_H + +#include "mbed.h" + +// LCD commands and definitions + +#define LCD_WIDTH 128 +#define LCD_HEIGHT 64 + +#define CMD_DISPLAY_OFF 0xAE +#define CMD_DISPLAY_ON 0xAF + +#define CMD_SET_DISP_START_LINE 0x40 +#define CMD_SET_PAGE 0xB0 + +#define CMD_SET_COLUMN_UPPER 0x10 +#define CMD_SET_COLUMN_LOWER 0x00 + +#define CMD_SET_ADC_NORMAL 0xA0 +#define CMD_SET_ADC_REVERSE 0xA1 + +#define CMD_SET_DISP_NORMAL 0xA6 +#define CMD_SET_DISP_REVERSE 0xA7 + +#define CMD_SET_ALLPTS_NORMAL 0xA4 +#define CMD_SET_ALLPTS_ON 0xA5 +#define CMD_SET_BIAS_9 0xA2 +#define CMD_SET_BIAS_7 0xA3 + +#define CMD_RMW 0xE0 +#define CMD_RMW_CLEAR 0xEE +#define CMD_INTERNAL_RESET 0xE2 +#define CMD_SET_COM_NORMAL 0xC0 +#define CMD_SET_COM_REVERSE 0xC8 +#define CMD_SET_POWER_CONTROL 0x28 +#define CMD_SET_RESISTOR_RATIO 0x20 +#define CMD_SET_VOLUME_FIRST 0x81 +#define CMD_SET_VOLUME_SECOND 0 +#define CMD_SET_STATIC_OFF 0xAC +#define CMD_SET_STATIC_ON 0xAD +#define CMD_SET_STATIC_REG 0x0 +#define CMD_SET_BOOSTER_FIRST 0xF8 +#define CMD_SET_BOOSTER_234 0 +#define CMD_SET_BOOSTER_5 1 +#define CMD_SET_BOOSTER_6 3 +#define CMD_NOP 0xE3 +#define CMD_TEST 0xF0 + +#define swap(a, b) { unsigned short t = a; a = b; b = t; } + +// ------------- Functions prototype ----------------- + + +void SPI_Write(uint8_t data); +void LCD_cmd(uint8_t command); +void LCD_data(uint8_t data); +void LCD_reset(void); +void LCD_set_contrast(unsigned int level); +void LCD_write_buffer(unsigned int *buffer); +void LCD_clear(void); +void LCD_setpixel(unsigned int *buff, uint8_t x, uint8_t y, uint8_t color); +void LCD_clearpixel(unsigned int *buff, uint8_t x, uint8_t y); +void LCD_drawline(unsigned int *buff, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color); +void LCD_drawchar(unsigned int *buff, uint8_t x, uint8_t line, char c); +void LCD_drawstring(unsigned int *buff, uint8_t x, uint8_t line, char *c); +void Clear_buffer(unsigned int *buff); + +#endif
diff -r e4d7342be507 -r bbc3e860fa3d ST7565_LCD/font_5x7.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ST7565_LCD/font_5x7.h Tue Feb 13 08:22:23 2018 +0000 @@ -0,0 +1,101 @@ + +#ifndef _SDA5708_FONT_5x7_H +#define _SDA5708_FONT_5x7_H + +const unsigned short font_PGM[] = { +0x00, 0x00, 0x00, 0x00, 0x00, // space (ASCII 0x20) +0x00, 0x00, 0x5f, 0x00, 0x00, // ! +0x00, 0x07, 0x00, 0x07, 0x00, // " +0x14, 0x7f, 0x14, 0x7f, 0x14, // # +0x24, 0x2a, 0x7f, 0x2a, 0x12, // $ +0xc4, 0xc8, 0x10, 0x26, 0x46, // % +0x36, 0x49, 0x55, 0x22, 0x50, // & +0x00, 0x05, 0x03, 0x00, 0x00, // ' +0x00, 0x1c, 0x22, 0x41, 0x00, // ( +0x00, 0x41, 0x22, 0x1c, 0x00, // ) ???? +0x14, 0x08, 0x3E, 0x08, 0x14, // * +0x08, 0x08, 0x3E, 0x08, 0x08, // + +0x00, 0x00, 0x50, 0x30, 0x00, // , +0x08, 0x08, 0x08, 0x08, 0x08, // - +0x00, 0x60, 0x60, 0x00, 0x00, // . +0x20, 0x10, 0x08, 0x04, 0x02, // / +0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 +0x00, 0x42, 0x7F, 0x40, 0x00, // 1 +0x42, 0x61, 0x51, 0x49, 0x46, // 2 +0x21, 0x41, 0x45, 0x4B, 0x31, // 3 +0x18, 0x14, 0x12, 0x7F, 0x10, // 4 +0x27, 0x45, 0x45, 0x45, 0x39, // 5 +0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 +0x01, 0x71, 0x09, 0x05, 0x03, // 7 +0x36, 0x49, 0x49, 0x49, 0x36, // 8 +0x06, 0x49, 0x49, 0x29, 0x1E, // 9 +0x00, 0x36, 0x36, 0x00, 0x00, // : +0x00, 0x56, 0x36, 0x00, 0x00, // ; +0x08, 0x14, 0x22, 0x41, 0x00, // < +0x14, 0x14, 0x14, 0x14, 0x14, // = +0x00, 0x41, 0x22, 0x14, 0x08, // > +0x02, 0x01, 0x51, 0x09, 0x06, // ? +0x32, 0x49, 0x59, 0x51, 0x3E, // @ +0x7E, 0x11, 0x11, 0x11, 0x7E, // A +0x7F, 0x49, 0x49, 0x49, 0x36, // B +0x3E, 0x41, 0x41, 0x41, 0x22, // C +0x7F, 0x41, 0x41, 0x22, 0x1C, // D +0x7F, 0x49, 0x49, 0x49, 0x41, // E +0x7F, 0x09, 0x09, 0x09, 0x01, // F +0x3E, 0x41, 0x49, 0x49, 0x7A, // G +0x7F, 0x08, 0x08, 0x08, 0x7F, // H +0x00, 0x41, 0x7F, 0x41, 0x00, // I +0x20, 0x40, 0x41, 0x3F, 0x01, // J +0x7F, 0x08, 0x14, 0x22, 0x41, // K +0x7F, 0x40, 0x40, 0x40, 0x40, // L +0x7F, 0x02, 0x0C, 0x02, 0x7F, // M +0x7F, 0x04, 0x08, 0x10, 0x7F, // N +0x3E, 0x41, 0x41, 0x41, 0x3E, // O +0x7F, 0x09, 0x09, 0x09, 0x06, // P +0x3E, 0x41, 0x51, 0x21, 0x5E, // Q +0x7F, 0x09, 0x19, 0x29, 0x46, // R +0x46, 0x49, 0x49, 0x49, 0x31, // S +0x01, 0x01, 0x7F, 0x01, 0x01, // T +0x3F, 0x40, 0x40, 0x40, 0x3F, // U +0x1F, 0x20, 0x40, 0x20, 0x1F, // V +0x3F, 0x40, 0x38, 0x40, 0x3F, // W +0x63, 0x14, 0x08, 0x14, 0x63, // X +0x07, 0x08, 0x70, 0x08, 0x07, // Y +0x61, 0x51, 0x49, 0x45, 0x43, // Z +0x00, 0x7F, 0x41, 0x41, 0x00, // [ +0x55, 0x2A, 0x55, 0x2A, 0x55, // 55 +0x00, 0x41, 0x41, 0x7F, 0x00, // ] +0x04, 0x02, 0x01, 0x02, 0x04, // ^ +0x40, 0x40, 0x40, 0x40, 0x40, // _ +0x00, 0x01, 0x02, 0x04, 0x00, // ' +0x20, 0x54, 0x54, 0x54, 0x78, // a +0x7F, 0x48, 0x44, 0x44, 0x38, // b +0x38, 0x44, 0x44, 0x44, 0x20, // c +0x38, 0x44, 0x44, 0x48, 0x7F, // d +0x38, 0x54, 0x54, 0x54, 0x18, // e +0x08, 0x7E, 0x09, 0x01, 0x02, // f +0x0C, 0x52, 0x52, 0x52, 0x3E, // g +0x7F, 0x08, 0x04, 0x04, 0x78, // h +0x00, 0x44, 0x7D, 0x40, 0x00, // i +0x20, 0x40, 0x44, 0x3D, 0x00, // j +0x7F, 0x10, 0x28, 0x44, 0x00, // k +0x00, 0x41, 0x7F, 0x40, 0x00, // l +0x7C, 0x04, 0x18, 0x04, 0x78, // m +0x7C, 0x08, 0x04, 0x04, 0x78, // n +0x38, 0x44, 0x44, 0x44, 0x38, // o +0x7C, 0x14, 0x14, 0x14, 0x08, // p +0x08, 0x14, 0x14, 0x18, 0x7C, // q +0x7C, 0x08, 0x04, 0x04, 0x08, // r +0x48, 0x54, 0x54, 0x54, 0x20, // s +0x04, 0x3F, 0x44, 0x40, 0x20, // t +0x3C, 0x40, 0x40, 0x20, 0x7C, // u +0x1C, 0x20, 0x40, 0x20, 0x1C, // v +0x3C, 0x40, 0x30, 0x40, 0x3C, // w +0x44, 0x28, 0x10, 0x28, 0x44, // x +0x0C, 0x50, 0x50, 0x50, 0x3C, // y +0x44, 0x64, 0x54, 0x4C, 0x44 // z + +}; + + +#endif
diff -r e4d7342be507 -r bbc3e860fa3d main.cpp --- a/main.cpp Tue May 16 05:18:55 2017 +0000 +++ b/main.cpp Tue Feb 13 08:22:23 2018 +0000 @@ -1,19 +1,297 @@ #include "mbed.h" #include "SDFileSystem.h" - -SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board +#include "ST7565_LCD.h" +#include "QEI.h" + +#define BAT_GAIN 6.80 +#define BAT_OFFS 0.0 + +PwmOut BEEP (D2); // Buzzer/speaker (PWM output) +PwmOut BKL (D3); // LCD backlight control (PMW output) +DigitalOut KAL (D0); // Keep-Alive/turn-off +DigitalOut BTC (D2); // Aux BT module control +DigitalIn Button (D4); // Pushbutton (digital input) +AnalogIn BATT (A0); // Battery monitor +AnalogIn ALS (A1); // Ambient Light sensor -int main() { - printf("Hello World!\n"); - - mkdir("/sd/mydir", 0777); +SDFileSystem sd(PB_15, PB_14, PB_13, PB_1, "sd"); // MOSI, MISO, SCK, CS + +// Quadrature encoder +QEI Wheel(D5, D6, NC, 16); + +// Tickers +Ticker Sec_Beat; // Timer ticker +Ticker Display_Refresh; // Display refresh ticker + +//Serial ports +Serial PC(USBTX, USBRX); // Virtual COM via USB +//Serial BT_module(D1, D0); // BlueTooth module + + +extern unsigned int buffer[128*64/8]; // RAM buffer used by LCD +time_t seconds; // timestamp +char Text[40]=""; // Text string used by LCD +float Vbatt, ALLevel; // battery votage and ambient light level + +// ------------------- Prototypes ----------------------- +void Timer_tick(void); +void Update_Display(void); +void Set_Time(void); +void Read_Voltages(void); +void PowerOff(void); + +int main() +{ + + KAL = 1; // ensure self-sustained power + //Button.mode(PullUp); // enable pushbutton pull-up + BKL.period_ms(3); // set LCD backlight PWM + BKL.write(1.0); + BEEP.period_us(2300); // set initial buzzer period and duty-cycle + BEEP.write(0.2); + Wheel.reset(); // clear encoder + LCD_reset(); + + // splash screen with date and time + sprintf(Text,__DATE__); + LCD_drawstring(buffer, 60, 5, Text); + sprintf(Text,__TIME__); + LCD_drawstring(buffer, 78, 6, Text); + LCD_write_buffer(buffer); + + + // enable LCD refresh ticker + Display_Refresh.attach(&Update_Display, 0.3); + + if(Button) // if pushbutton is pressed + Set_Time(); // set RTC time and date + + wait(2); + Clear_buffer(buffer); + BKL.write(0.5); - FILE *fp = fopen("/sd/mydir/sdtest.txt", "w"); + //PowerOff(); // Power-off test + + + // enable sec-beat ticker + Sec_Beat.attach(&Timer_tick, 1); + + + + printf("Hello World!\n"); + mkdir("/sd/system", 0777); + FILE *fp = fopen("/sd/system/sdlog.txt", "w"); if(fp == NULL) { error("Could not open file for write\n"); } fprintf(fp, "Hello fun SD Card World!"); fclose(fp); - printf("Goodbye World!\n"); + + while(1) + { + // dance + } + + } + + +//=========================================================================== + +// ------------- Called every second ---------------------- + +void Timer_tick() +{ + seconds = time(NULL); + strftime(Text, 50, "%d-%b-%Y %H:%M:%S", localtime(&seconds)); + LCD_drawstring(buffer, 0, 0, Text); + + // read voltages + Read_Voltages(); + + // write values to buffer + sprintf(Text,"VBATT= %4.2f", Vbatt); + LCD_drawstring(buffer, 0, 2, Text); + sprintf(Text,"ALL= %4.2f", ALLevel); + LCD_drawstring(buffer, 0, 3, Text); + + // Send data to COM port + //PC.printf("Tset= %3.0f, Tpit= %3.0f, Tmeat= %3.0f, PWM= %3.0f\n",Tset, Tpit, Tmeat, FanSpeed); + + //LCD_write_buffer(buffer); // LCD update + + return; +} + + +//--------------------------------------------------------------------------- +void Update_Display(void) +{ + LCD_write_buffer(buffer); // LCD update + return; +} + +//--------------------------------------------------------------------------- +void Set_Time(void) +{ + uint8_t Year=0, Month=0, Day=0, Hours=0, Mins=0, Secs=0; + time_t seconds; + struct tm t; + + sprintf(Text,"TIME & DATE SETTING"); + LCD_drawstring(buffer, 0, 0, Text); + + // Set year + while(Button); + wait_ms(50); + + while(!Button) + { + if(int(Wheel.getPulses())<0) + Wheel.reset(); + Year = (uint8_t)(Wheel.getPulses()); + + if(Year>99) + Wheel.reset(); + + sprintf(Text, "Year: %2d", Year); + LCD_drawstring(buffer, 0, 2, Text); + + } + + // Set month + while(Button); + wait_ms(50); + Wheel.reset(); + while(!Button) + { + if(int(Wheel.getPulses())<0) + Wheel.reset(); + Month = (uint8_t)(Wheel.getPulses()/2); + + if(Month>11) + Wheel.reset(); + + sprintf(Text, "Month: %2d", Month+1); + LCD_drawstring(buffer, 0, 3, Text); + + } + + + // Set day + while(Button); + wait_ms(50); + Wheel.reset(); + while(!Button) + { + if(int(Wheel.getPulses())<0) + Wheel.reset(); + Day = (uint8_t)(Wheel.getPulses()/2); + + if(Day>30) + Wheel.reset(); + + sprintf(Text, "Day: %2d", Day+1); + LCD_drawstring(buffer, 0, 4, Text); + + } + + // Set hours + while(Button); + wait_ms(50); + Wheel.reset(); + while(!Button) + { + if(int(Wheel.getPulses())<0) + Wheel.reset(); + Hours = (uint8_t)(Wheel.getPulses()/2); + + if(Hours>22) + Wheel.reset(); + + sprintf(Text, "Hours: %2d", Hours+1); + LCD_drawstring(buffer, 0, 5, Text); + + } + Hours++; + + // Set minutes + while(Button); + wait_ms(50); + Wheel.reset(); + while(!Button) + { + if(int(Wheel.getPulses())<0) + Wheel.reset(); + Mins = (uint8_t)(Wheel.getPulses()/2); + + if(Mins>59) + Wheel.reset(); + + sprintf(Text, "Minutes: %2d", Mins); + LCD_drawstring(buffer, 0, 6, Text); + + } + + t.tm_year = Year + 100; + t.tm_mon = Month; + t.tm_mday = Day + 1; + t.tm_hour = Hours; + t.tm_min = Mins; + t.tm_sec = Secs; + + seconds = mktime(&t); + set_time(seconds); + + return; +} + + +//--------------------------------------------------------------------------- +void Read_Voltages(void) +{ + + double ADC_value; + uint8_t smooth = 10; // Number of samples to smooth + uint8_t i; + + // Read battery voltage + + ADC_value = BATT.read(); // cleanup + wait_ms(50); + ADC_value = 0; + for(i=0;i<smooth;i++) + ADC_value += BATT.read(); + + ADC_value = ADC_value/smooth; + Vbatt = (float)(ADC_value*BAT_GAIN)+BAT_OFFS; + + + // Read Ambient Light Level + + ADC_value = ALS.read(); // cleanup + wait_ms(50); + ADC_value = 0; + for(i=0;i<smooth;i++) + ADC_value += ALS.read(); + + ADC_value = ADC_value/smooth; + ALLevel = (float)(ADC_value); + +return; +} + + +//--------------------------------------------------------------------------- +void PowerOff(void) +{ + BKL.write(1); + Clear_buffer(buffer); + sprintf(Text,"POWERING OFF"); + LCD_drawstring(buffer, 20, 3, Text); + LCD_write_buffer(buffer); + wait(2); + + KAL = 0; +} \ No newline at end of file