From fd8c0b284d4e790b0b2f41b55f80b316707f98a5 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 19 Jan 2013 18:42:05 +0100 Subject: digital/ucoolib/ucoolib/dev/avrisp: add AVR ISP --- digital/ucoolib/ucoolib/dev/avrisp/Config | 6 + digital/ucoolib/ucoolib/dev/avrisp/Module | 1 + digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc | 452 +++++++++++++++++++++ digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh | 247 +++++++++++ digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc | 173 ++++++++ digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh | 95 +++++ digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc | 269 ++++++++++++ digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh | 50 +++ digital/ucoolib/ucoolib/dev/avrisp/test/Makefile | 9 + .../ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc | 90 ++++ 10 files changed, 1392 insertions(+) create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/Config create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/Module create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/test/Makefile create mode 100644 digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc (limited to 'digital/ucoolib') diff --git a/digital/ucoolib/ucoolib/dev/avrisp/Config b/digital/ucoolib/ucoolib/dev/avrisp/Config new file mode 100644 index 00000000..cf3eb48a --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/Config @@ -0,0 +1,6 @@ +[dev/avrisp] +frame_buffer_size = 281 +proto_signature = "APBisp_2" +proto_build_number = 0x0100 +proto_hw_version = 0x02 +proto_sw_version = 0x0204 diff --git a/digital/ucoolib/ucoolib/dev/avrisp/Module b/digital/ucoolib/ucoolib/dev/avrisp/Module new file mode 100644 index 00000000..d66f06f3 --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/Module @@ -0,0 +1 @@ +dev_avrisp_SOURCES := avrisp.cc avrisp_proto.cc avrisp_frame.cc diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc new file mode 100644 index 00000000..10550687 --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc @@ -0,0 +1,452 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "avrisp.hh" + +#include "ucoolib/utils/delay.hh" + +namespace ucoo { + +/// Command used to load extended address. +static const uint8_t avrisp_cmd_load_extended_address = 0x4d; +/// Bit to address high byte. +static const uint8_t avrisp_cmd_high_byte = 1 << 3; +/// Extra EEPROM programming delay. +static const int avrisp_eeprom_delay_ms = 2; +/// Miscellaneous read delay. +static const int avrisp_misc_read_delay_ms = 5; + +AvrIsp::AvrIsp (AvrIspIntf &intf) + : intf_ (intf) +{ +} + +AvrIspResult +AvrIsp::enter_progmode (uint8_t sck_duration_us, uint8_t timeout_ms, + uint8_t stab_delay_ms, uint8_t cmd_exe_delay_ms, + uint8_t synch_loops, uint8_t byte_delay_ms, + uint8_t poll_value, uint8_t poll_index, + const uint8_t cmd[4]) +{ + int i; + uint8_t tmp1, tmp2; + // Reset context. + ext_addr_ = 0; + last_ext_addr_ = 0xff; + larger_than_64k_ = 0; + bytes_left_ = 0; + // Enable SPI. + intf_.enable (sck_duration_us); + delay_ms (stab_delay_ms); + // Limit the number of loops. + if (synch_loops > 48) + synch_loops = 48; + // Minimum byte delay. + if (byte_delay_ms < 1) + byte_delay_ms = 1; + // Synchronisation loops. + for (i = 0; i < synch_loops; i++) + { + delay_ms (cmd_exe_delay_ms); + intf_.send_and_recv (cmd[0]); + delay_ms (byte_delay_ms); + intf_.send_and_recv (cmd[1]); + delay_ms (byte_delay_ms); + tmp1 = intf_.send_and_recv (cmd[2]); + delay_ms (byte_delay_ms); + tmp2 = intf_.send_and_recv (cmd[3]); + // Test success. + if (poll_index == 0 + || (poll_index == 3 && tmp1 == poll_value) + || (poll_index != 3 && tmp2 == poll_value)) + return AVRISP_OK; + // Else, new try. + intf_.sck_pulse (); + delay_ms (20); + } + return AVRISP_FAILED; +} + +void +AvrIsp::leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms) +{ + delay_ms (pre_delay_ms); + intf_.disable (); + delay_ms (post_delay_ms); +} + +void +AvrIsp::load_address (uint32_t addr) +{ + addr_ = addr & 0xffff; + ext_addr_ = (addr >> 16) & 0xff; + last_ext_addr_ = 0xff; + larger_than_64k_ = (addr & 0x80000000) ? 1 : 0; +} + +AvrIspResult +AvrIsp::chip_erase (uint8_t erase_delay_ms, uint8_t poll_method, + const uint8_t cmd[4]) +{ + int tries; + intf_.send_and_recv (cmd[0]); + intf_.send_and_recv (cmd[1]); + intf_.send_and_recv (cmd[2]); + intf_.send_and_recv (cmd[3]); + if (poll_method == 0) + { + // Use delay. + delay_ms (erase_delay_ms); + } + else + { + // Use RDY/BSY command. + tries = 150; + while ((spi_tx_32 (0xf0000000) & 1) && tries) + tries--; + if (tries == 0) + return AVRISP_TIMEOUT; + } + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::program_begin (uint16_t num_bytes, uint8_t mode, uint8_t delay_ms, + uint8_t cmd_write_mem, uint8_t cmd_write_page, + uint8_t cmd_read_mem, const uint8_t poll[2], + uint8_t flash) +{ + // Set delay bounds. + if (delay_ms < 4) + delay_ms = 4; + if (delay_ms > 32) + delay_ms = 32; + // Check data size. + if (flash && (num_bytes & 1)) + return AVRISP_FAILED; + // Store parameters. + start_addr_ = addr_; + bytes_left_ = num_bytes; + mode_ = mode; + delay_ms_ = delay_ms; + cmd_write_mem_ = cmd_write_mem; + cmd_write_page_ = cmd_write_page; + cmd_read_mem_ = cmd_read_mem; + poll_[0] = poll[0]; + poll_[1] = poll[1]; + pollable_ = 0; + flash_ = flash; + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::program_flash_begin (uint16_t num_bytes, uint8_t mode, + uint8_t delay_ms, uint8_t cmd_write_mem, + uint8_t cmd_write_page, uint8_t cmd_read_mem, + const uint8_t poll[2]) +{ + return program_begin (num_bytes, mode, delay_ms, cmd_write_mem, + cmd_write_page, cmd_read_mem, poll, 1); +} + +AvrIspResult +AvrIsp::program_eeprom_begin (uint16_t num_bytes, uint8_t mode, + uint8_t delay_ms, uint8_t cmd_write_mem, + uint8_t cmd_write_page, uint8_t cmd_read_mem, + const uint8_t poll[2]) +{ + return program_begin (num_bytes, mode, delay_ms, cmd_write_mem, + cmd_write_page, cmd_read_mem, poll, 0); +} + +AvrIspResult +AvrIsp::program_continue (const uint8_t *data, uint16_t size) +{ + uint16_t i; + uint8_t read; + int tries; + // Check size. + if (size > bytes_left_ || (flash_ && (size & 1))) + return AVRISP_FAILED; + bytes_left_ -= size; + // Loop on each input bytes. + for (i = 0; i < size; i++) + { + // Check for Load Extended Address. + if (larger_than_64k_ && last_ext_addr_ != ext_addr_) + { + intf_.send_and_recv (avrisp_cmd_load_extended_address); + intf_.send_and_recv (0x00); + intf_.send_and_recv (ext_addr_); + intf_.send_and_recv (0x00); + last_ext_addr_ = ext_addr_; + } + // Write memory/load page, using bit 3 as byte selector. + if (flash_ && (i & 1)) + intf_.send_and_recv (cmd_write_mem_ | avrisp_cmd_high_byte); + else + intf_.send_and_recv (cmd_write_mem_); + spi_tx_16 (addr_); + intf_.send_and_recv (data[i]); + // EEPROM needs more delay. + if (!flash_) + delay_ms (avrisp_eeprom_delay_ms); + // Poll. + if (!(mode_ & AVRISP_MODE_PAGE)) + { + // Poll right now. + tries = 150; + read = poll_[0]; + if ((mode_ & AVRISP_MODE_WORD_VALUE) && data[i] != read) + { + // Poll by reading byte. + while (read != data[i] && tries) + { + if (flash_ && (i & 1)) + intf_.send_and_recv (cmd_read_mem_ + | avrisp_cmd_high_byte); + else + intf_.send_and_recv (cmd_read_mem_); + spi_tx_16 (addr_); + read = intf_.send_and_recv (0x00); + tries--; + } + } + else if (mode_ & AVRISP_MODE_WORD_RDY_BSY) + { + // RDY/BSY polling. + while ((spi_tx_32 (0xf0000000) & 1) && tries) + tries--; + } + else + // Simple delay. + delay_ms (delay_ms_); + if (tries == 0) + return AVRISP_TIMEOUT; + } + else + { + // Check for poll method. + if (!pollable_ && data[i] != poll_[0]) + { + pollable_ = 0x02 | (i & 1); + poll_addr_ = addr_; + } + } + // Increment address. + if (!flash_ || (i & 1)) + { + addr_++; + if (addr_ == 0) + ext_addr_++; + } + } + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::program_end () +{ + uint8_t read; + int tries; + // Check size. + if (bytes_left_ != 0) + return AVRISP_FAILED; + // Write page if requested. + if ((mode_ & (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE)) + == (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE)) + { + // Write page. + intf_.send_and_recv (cmd_write_page_); + spi_tx_16 (start_addr_); + intf_.send_and_recv (0x00); + // EEPROM needs more delay. + if (!flash_) + delay_ms (avrisp_eeprom_delay_ms); + // Poll. + tries = 150; + read = poll_[0]; + if ((mode_ & AVRISP_MODE_PAGE_VALUE) && pollable_) + { + // Poll by reading byte. + while (read == poll_[0] && tries) + { + if (flash_ && (pollable_ & 1)) + intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte); + else + intf_.send_and_recv (cmd_read_mem_); + spi_tx_16 (poll_addr_); + read = intf_.send_and_recv (0x00); + tries--; + } + } + else if (mode_ & AVRISP_MODE_PAGE_RDY_BSY) + { + // RDY/BSY polling. + while ((spi_tx_32 (0xf0000000) & 1) && tries) + tries--; + } + else + // Simple delay. + delay_ms (delay_ms_); + if (tries == 0) + return AVRISP_TIMEOUT; + } + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::read_begin (uint16_t num_bytes, uint8_t cmd_read_mem, uint8_t flash) +{ + // Check data size. + if (flash && (num_bytes & 1)) + return AVRISP_FAILED; + // Store parameters. + bytes_left_ = num_bytes; + cmd_read_mem_ = cmd_read_mem; + flash_ = flash; + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem) +{ + return read_begin (num_bytes, cmd_read_mem, 1); +} + +AvrIspResult +AvrIsp::read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem) +{ + return read_begin (num_bytes, cmd_read_mem, 0); +} + +AvrIspResult +AvrIsp::read_continue (uint8_t *data, uint16_t size) +{ + uint16_t i; + // Check size. + if (size > bytes_left_ || (flash_ && (size & 1))) + return AVRISP_FAILED; + bytes_left_ -= size; + // Loop on each bytes. + for (i = 0; i < size; i++) + { + // Check for Load Extended Address. + if (larger_than_64k_ && last_ext_addr_ != ext_addr_) + { + intf_.send_and_recv (avrisp_cmd_load_extended_address); + intf_.send_and_recv (0x00); + intf_.send_and_recv (ext_addr_); + intf_.send_and_recv (0x00); + last_ext_addr_ = ext_addr_; + } + // Read memory, using bit 3 as byte selector. + if (flash_ && (i & 1)) + intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte); + else + intf_.send_and_recv (cmd_read_mem_); + spi_tx_16 (addr_); + data[i] = intf_.send_and_recv (0x00); + // Increment address. + if (!flash_ || (i & 1)) + { + addr_++; + if (addr_ == 0) + ext_addr_++; + } + } + return AVRISP_OK; +} + +AvrIspResult +AvrIsp::read_end () +{ + // Check size. + if (bytes_left_ != 0) + return AVRISP_FAILED; + return AVRISP_OK; +} + +void +AvrIsp::program_misc (const uint8_t cmd[4]) +{ + uint8_t i; + for (i = 0; i < 4; i++) + intf_.send_and_recv (cmd[i]); +} + +uint8_t +AvrIsp::read_misc (uint8_t ret_addr, const uint8_t cmd[4]) +{ + uint8_t i, read = 0, tmp; + for (i = 0; i < 4; i++) + { + tmp = intf_.send_and_recv (cmd[i]); + if (i == ret_addr) + read = tmp; + delay_ms (avrisp_misc_read_delay_ms); + } + return read; +} + +void +AvrIsp::multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start, + const uint8_t *dout, uint8_t *din) +{ + uint8_t in, out; + while (num_tx || num_rx) + { + out = 0; + if (num_tx) + { + out = *dout++; + num_tx--; + } + in = intf_.send_and_recv (out); + if (rx_start) + rx_start--; + else if (num_rx) + { + *din++ = in; + num_rx--; + } + } +} + +void +AvrIsp::spi_tx_16 (uint16_t data) +{ + intf_.send_and_recv ((data >> 8) & 0xff); + intf_.send_and_recv ((data >> 0) & 0xff); +} + +uint8_t +AvrIsp::spi_tx_32 (uint32_t data) +{ + intf_.send_and_recv ((data >> 24) & 0xff); + intf_.send_and_recv ((data >> 16) & 0xff); + intf_.send_and_recv ((data >> 8) & 0xff); + return intf_.send_and_recv ((data >> 0) & 0xff); +} + +} // namespace ucoo diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh new file mode 100644 index 00000000..5046459b --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh @@ -0,0 +1,247 @@ +#ifndef ucoolib_dev_avrisp_avrisp_hh +#define ucoolib_dev_avrisp_avrisp_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "ucoolib/common.hh" + +namespace ucoo { + +/// Results returned by ISP functions. +enum AvrIspResult +{ + /// Operation success. + AVRISP_OK, + /// Operation failed. + AVRISP_FAILED, + /// Operation failed on a timeout. + AVRISP_TIMEOUT, +}; + +/// ISP Programming mode. +enum AvrIspMode +{ + /// Use page programming. + AVRISP_MODE_PAGE = 1, + /// Use simple delay for word programming. + AVRISP_MODE_WORD_DELAY = 2, + /// Use value polling if possible for word programming, fall back to delay + /// if not possible. + AVRISP_MODE_WORD_VALUE = 4, + /// Use RDY/BSY polling for word programming. + AVRISP_MODE_WORD_RDY_BSY = 8, + /// Use simple delay for page programming. + AVRISP_MODE_PAGE_DELAY = 16, + /// Use value polling if possible for page programming, fall back to delay + /// if not possible. + AVRISP_MODE_PAGE_VALUE = 32, + /// Use RDY/BSY polling for page programming. + AVRISP_MODE_PAGE_RDY_BSY = 64, + /// Write page at end of transfer. Used for big pages which must be + /// transfered in several packets. + AVRISP_MODE_PAGE_WRITE = 128, +}; + +/// Interface to hardware connection. +class AvrIspIntf +{ + public: + /// Send and receive one byte through SPI interface. + virtual uint8_t send_and_recv (uint8_t tx) = 0; + /// Enable programming: + /// - set RESET and SCK to low, + /// - power on, or if not possible, do a positive RESET pulse, + /// - enable SPI, mode 0. + virtual void enable (uint8_t sck_duration_us) = 0; + /// Disable programming: + /// - disable SPI, + /// - release RESET, + /// - power off if desired. + virtual void disable () = 0; + /// Do a pulse on SCK. This is used to try to resynchronise. + virtual void sck_pulse () = 0; +}; + +/// AVR serial programming. +class AvrIsp +{ + public: + /// Constructor. + AvrIsp (AvrIspIntf &intf); + /// Enable SPI port and enter programing mode. + /// - sck_duration_us: SCK period. + /// - timeout_ms: command time-out, unused. + /// - stab_delay_ms: stabilisation delay once device is reseted and SPI + /// initialised. + /// - cmd_exe_delay_ms: delay for the command execution. + /// - synch_loops: number of synchronisation loops (there is no start of + /// frame in SPI). + /// - byte_delay_ms: delay between each byte. + /// - poll_value: value to read to consider the sequence is correct. + /// - poll_index: transfer index at which the poll_value must be read. + /// - cmd: command bytes to be transfered. + /// - returns: AVRISP_OK or AVRISP_FAILED if no synchronisation. + AvrIspResult enter_progmode (uint8_t sck_duration_us, + uint8_t timeout_ms, uint8_t stab_delay_ms, + uint8_t cmd_exe_delay_ms, + uint8_t synch_loops, uint8_t byte_delay_ms, + uint8_t poll_value, uint8_t poll_index, + const uint8_t cmd[4]); + /// Leave programming mode and disable SPI port. + /// - pre_delay_ms: delay before disabling. + /// - post_delay_ms: delay after disabling. + void leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms); + /// Load programing address. + /// - addr: address to load, bit 31 means the device has more than 64k + /// words and extended addressing should be used. + void load_address (uint32_t addr); + /// Chip full erase. + /// - erase_delay_ms: delay to ensure the erase is finished. + /// - poll_method: use delay (0) or RDY/BSY polling (1). + /// - cmd: chip erase command. + /// - returns: AVRISP_OK or AVRISP_TIMEOUT if using polling and it + /// timed-out. + AvrIspResult chip_erase (uint8_t erase_delay_ms, uint8_t poll_method, + const uint8_t cmd[4]); + /// Start a program command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult program_begin (uint16_t num_bytes, uint8_t mode, + uint8_t delay_ms, uint8_t cmd_write_mem, + uint8_t cmd_write_page, uint8_t cmd_read_mem, + const uint8_t poll[2], uint8_t flash); + /// Start a flash memory program command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult program_flash_begin (uint16_t num_bytes, uint8_t mode, + uint8_t delay_ms, uint8_t cmd_write_mem, + uint8_t cmd_write_page, + uint8_t cmd_read_mem, + const uint8_t poll[2]); + /// Start a EEPROM memory program command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult program_eeprom_begin (uint16_t num_bytes, + uint8_t mode, + uint8_t delay_ms, + uint8_t cmd_write_mem, + uint8_t cmd_write_page, + uint8_t cmd_read_mem, + const uint8_t poll[2]); + /// Provide data for memory programming. Data should be given by even + /// sized packs or loading of word addressed data will fail. + /// - returns: AVRISP_OK, AVRISP_FAILED for bad parameters or + /// AVRISP_TIMEOUT if using polling and it timed-out. + AvrIspResult program_continue (const uint8_t *data, uint16_t size); + /// End program command. + /// - returns: AVRISP_OK, AVRISP_FAILED if too early or AVRISP_TIMEOUT if + /// using polling and it timed-out. + AvrIspResult program_end (); + /// Start a read command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult read_begin (uint16_t num_bytes, uint8_t cmd_read_mem, + uint8_t flash); + /// Start a flash memory read command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem); + /// Start a EEPROM memory read command. + /// - num_bytes: total number of bytes to program. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + /// See class for other parameters meaning. + AvrIspResult read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem); + /// Get data from read memory. Data should be read by even sized packs or + /// loading of word addressed data will fail. + /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters. + AvrIspResult read_continue (uint8_t *data, uint16_t size); + /// End read command. + /// - returns: AVRISP_OK or AVRISP_FAILED if too early. + AvrIspResult read_end (); + /// Program miscellaneous memory (fuse, lock). + /// - cmd: program command. + void program_misc (const uint8_t cmd[4]); + /// Read miscellaneous memory (fuse, lock, signature, osccal). + /// - ret_addr: transfer index at which the return value must be read. + /// - cmd: read command. + uint8_t read_misc (uint8_t ret_addr, const uint8_t cmd[4]); + /// Generic SPI access. + /// - num_tx: number of bytes to transmit. + /// - num_rx: number of bytes to receive. + /// - rx_start: start reception after this number of transmitted bytes. + /// - dout: buffer to read sent bytes. + /// - din: buffer to write received bytes. + /// Limitation: no support for doing this in several chunks as memory + /// programing and reading. + void multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start, + const uint8_t *dout, uint8_t *din); + private: + /// Transmit a 16 bit data. + void spi_tx_16 (uint16_t data); + /// Transmit a 32 bit data and return last byte received. This is used for + /// RDY/BSY polling. + uint8_t spi_tx_32 (uint32_t data); + private: + /// Hardware interface. + AvrIspIntf &intf_; + /// Current address. + uint16_t addr_; + /// Current extended address. + uint8_t ext_addr_; + /// Extended address loaded in device. + uint8_t last_ext_addr_; + /// Whether the device needs extended addressing. + uint8_t larger_than_64k_; + /// Programming start address (used for page program command). + uint16_t start_addr_; + /// Number of bytes left to process. + uint16_t bytes_left_; + /// Programming mode. + uint8_t mode_; + /// Programming delay if no other poll method. + uint8_t delay_ms_; + /// Write Program Memory or Load Page. + uint8_t cmd_write_mem_; + /// Write Page. + uint8_t cmd_write_page_; + /// Read Program Memory. + uint8_t cmd_read_mem_; + /// Value read until memory is programmed for value polling. + uint8_t poll_[2]; + /// Whether the page can be polled (if almost one byte is not poll[0]). + /// This is non zero if true, with LSB = 1 for high byte. + uint8_t pollable_; + /// Address to use for polling. + uint16_t poll_addr_; + /// Whether this is a flash memory. + uint8_t flash_; +}; + +} // namespace ucoo + +#endif // ucoolib_dev_avrisp_avrisp_hh diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc new file mode 100644 index 00000000..04a1f1a5 --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc @@ -0,0 +1,173 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "avrisp_frame.hh" + +namespace ucoo { + +static const uint8_t avrisp_frame_proto_start = 27; +static const uint8_t avrisp_frame_proto_token = 14; +static const uint8_t avrisp_frame_proto_answer_cksum_error = 0xb0; +static const uint8_t avrisp_frame_proto_status_cksum_error = 0xc1; + +AvrIspFrame::AvrIspFrame (AvrIspProto &proto) + : proto_ (proto), state_ (AVRISP_FRAME_STATE_START), buffer_send_index_ (-1) +{ +} + +void +AvrIspFrame::read_and_write (Stream &stream) +{ + // Design is inherited from byte based C interface. + while (1) + { + if (buffer_send_index_ == -1) + { + // Read. + int c = stream.getc (); + if (c == -1) + return; + else + accept_char (c); + } + else + { + // Write. + int r = stream.write (reinterpret_cast (buffer_) + + buffer_send_index_, + buffer_len_ - buffer_send_index_); + if (r <= 0) + return; + else + buffer_send_index_ += r; + if (buffer_send_index_ == buffer_len_) + buffer_send_index_ = -1; + } + } +} + +inline AvrIspFrameState +operator++ (AvrIspFrameState& state, int) +{ + const int i = static_cast (state); + state = static_cast (i + 1); + return state; +} + +void +AvrIspFrame::accept_char (uint8_t c) +{ + switch (state_) + { + case AVRISP_FRAME_STATE_START: + if (c == avrisp_frame_proto_start) + { + cksum_ = avrisp_frame_proto_start; + state_++; + } + break; + case AVRISP_FRAME_STATE_WAIT_SEQ: + cksum_ ^= c; + seq_ = c; + state_++; + break; + case AVRISP_FRAME_STATE_WAIT_LEN_MSB: + cksum_ ^= c; + len_ = c << 8; + state_++; + break; + case AVRISP_FRAME_STATE_WAIT_LEN_LSB: + cksum_ ^= c; + len_ |= c; + buffer_len_ = 0; + if (len_ == 0 + || len_ > (UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE - proto_head_ + - proto_tail_)) + state_ = AVRISP_FRAME_STATE_START; + else + state_++; + break; + case AVRISP_FRAME_STATE_WAIT_TOKEN: + if (c == avrisp_frame_proto_token) + { + cksum_ ^= c; + state_++; + } + else + state_ = AVRISP_FRAME_STATE_START; + break; + case AVRISP_FRAME_STATE_DATA: + cksum_ ^= c; + buffer_[proto_head_ + buffer_len_++] = c; + if (buffer_len_ == len_) + state_++; + break; + case AVRISP_FRAME_STATE_WAIT_CKSUM: + cksum_ ^= c; + state_ = AVRISP_FRAME_STATE_START; + process (); + break; + } +} + +void +AvrIspFrame::send_frame (int len) +{ + int i = 0; + uint8_t cksum; + buffer_[i++] = avrisp_frame_proto_start; + cksum = avrisp_frame_proto_start; + buffer_[i++] = seq_; + cksum ^= seq_; + buffer_[i++] = len >> 8; + cksum ^= len >> 8; + buffer_[i++] = len & 0xff; + cksum ^= len & 0xff; + buffer_[i++] = avrisp_frame_proto_token; + cksum ^= avrisp_frame_proto_token; + for (; i < proto_head_ + len; i++) + cksum ^= buffer_[i]; + buffer_[i] = cksum; + buffer_len_ = proto_head_ + len + proto_tail_; + buffer_send_index_ = 0; +} + +void +AvrIspFrame::process () +{ + if (cksum_ != 0) + { + /* Bad checksum. */ + buffer_[proto_head_] = avrisp_frame_proto_answer_cksum_error; + buffer_[proto_head_ + 1] = avrisp_frame_proto_status_cksum_error; + send_frame (2); + } + else + { + int r = proto_.accept (buffer_ + proto_head_, buffer_len_); + if (r) + send_frame (r); + } +} + +} // namespace ucoo diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh new file mode 100644 index 00000000..c51e42df --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh @@ -0,0 +1,95 @@ +#ifndef ucoolib_dev_avrisp_avrisp_frame_hh +#define ucoolib_dev_avrisp_avrisp_frame_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "avrisp_proto.hh" + +#include "ucoolib/intf/stream.hh" + +#include "config/dev/avrisp.hh" + +namespace ucoo { + +/// State of frame decoding. +enum AvrIspFrameState +{ + /// Start state, nothing decoded. + AVRISP_FRAME_STATE_START, + /// After message started, waiting sequence number. + AVRISP_FRAME_STATE_WAIT_SEQ, + /// Waiting first length byte. + AVRISP_FRAME_STATE_WAIT_LEN_MSB, + /// Waiting second length byte. + AVRISP_FRAME_STATE_WAIT_LEN_LSB, + /// Waiting token. + AVRISP_FRAME_STATE_WAIT_TOKEN, + /// Reading data. + AVRISP_FRAME_STATE_DATA, + /// Waiting checksum. + AVRISP_FRAME_STATE_WAIT_CKSUM, +}; + +/// Transfer data between a Stream and AvrIspProto which works frame by frame. +class AvrIspFrame +{ + public: + /// Constructor. + AvrIspFrame (AvrIspProto &proto); + /// Read & write from stream. If operation on stream blocks, this will + /// block too. + void read_and_write (Stream &stream); + private: + /// Handle received char. + void accept_char (uint8_t c); + /// Send frame in buffer (actually just setup, work is done in + /// read_and_write()). + void send_frame (int len); + /// Process found received frame. + void process (); + private: + /// Frame based ISP protocol handler. + AvrIspProto &proto_; + /// Current state. + AvrIspFrameState state_; + /// Message sequence number. + uint8_t seq_; + /// Message length. + int len_; + /// Checksum current value. + uint8_t cksum_; + /// Buffer to store frame until validated. + uint8_t buffer_[UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE]; + /// Used buffer length. + int buffer_len_; + /// Index to first byte to send from buffer, or -1 if not sending. + int buffer_send_index_; + /// Size of the frame header. + static const uint8_t proto_head_ = 5; + /// Size of the frame tail. + static const uint8_t proto_tail_ = 1; +}; + +} // namespace ucoo + +#endif // ucoolib_dev_avrisp_avrisp_frame_hh diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc new file mode 100644 index 00000000..9c025d3c --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc @@ -0,0 +1,269 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "avrisp_proto.hh" + +#include "ucoolib/utils/bytes.hh" + +#include "config/dev/avrisp.hh" + +#include +#include + +namespace ucoo { + +/// Protocol commands. +enum AvrIspProtoCmd +{ + AVRISP_PROTO_CMD_SIGN_ON = 0x01, + AVRISP_PROTO_CMD_SET_PARAMETER = 0x02, + AVRISP_PROTO_CMD_GET_PARAMETER = 0x03, + AVRISP_PROTO_CMD_SET_DEVICE_PARAMETERS = 0x04, + AVRISP_PROTO_CMD_OSCCAL = 0x05, + AVRISP_PROTO_CMD_LOAD_ADDRESS = 0x06, + AVRISP_PROTO_CMD_FIRMWARE_UPGRADE = 0x07, + AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP = 0x10, + AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP = 0x11, + AVRISP_PROTO_CMD_CHIP_ERASE_ISP = 0x12, + AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP = 0x13, + AVRISP_PROTO_CMD_READ_FLASH_ISP = 0x14, + AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP = 0x15, + AVRISP_PROTO_CMD_READ_EEPROM_ISP = 0x16, + AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP = 0x17, + AVRISP_PROTO_CMD_READ_FUSE_ISP = 0x18, + AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP = 0x19, + AVRISP_PROTO_CMD_READ_LOCK_ISP = 0x1a, + AVRISP_PROTO_CMD_READ_SIGNATURE_ISP = 0x1b, + AVRISP_PROTO_CMD_READ_OSCCAL_ISP = 0x1c, + AVRISP_PROTO_CMD_SPI_MULTI = 0x1d, +}; + +/// Protocol command status. +enum AvrIspProtoStatus +{ + AVRISP_PROTO_STATUS_CMD_OK = 0x00, + + AVRISP_PROTO_STATUS_CMD_TOUT = 0x80, + AVRISP_PROTO_STATUS_RDY_BSY_TOUT = 0x81, + AVRISP_PROTO_STATUS_SET_PARAM_MISSING = 0x82, + + AVRISP_PROTO_STATUS_CMD_FAILED = 0xc0, + AVRISP_PROTO_STATUS_CKSUM_ERROR = 0xc1, + AVRISP_PROTO_STATUS_CMD_UNKNOWN = 0xc9, +}; + +/// Protocol parameters. +enum AvrIspProtoParam +{ + AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW = 0x80, + AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH = 0x81, + AVRISP_PROTO_PARAM_HW_VER = 0x90, + AVRISP_PROTO_PARAM_SW_MAJOR = 0x91, + AVRISP_PROTO_PARAM_SW_MINOR = 0x92, + AVRISP_PROTO_PARAM_VTARGET = 0x94, + AVRISP_PROTO_PARAM_VADJUST = 0x95, + AVRISP_PROTO_PARAM_OSC_PSCALE = 0x96, + AVRISP_PROTO_PARAM_OSC_CMATCH = 0x97, + AVRISP_PROTO_PARAM_SCK_DURATION = 0x98, + AVRISP_PROTO_PARAM_TOPCARD_DETECT = 0x9a, + AVRISP_PROTO_PARAM_STATUS = 0x9c, + AVRISP_PROTO_PARAM_DATA = 0x9d, + AVRISP_PROTO_PARAM_RESET_POLARITY = 0x9e, + AVRISP_PROTO_PARAM_CONTROLLER_INIT = 0x9f, +}; + +static inline AvrIspProtoStatus +avrisp_proto_isp_status (AvrIspResult isp_status) +{ + if (isp_status == AVRISP_OK) + return AVRISP_PROTO_STATUS_CMD_OK; + else if (isp_status == AVRISP_TIMEOUT) + return AVRISP_PROTO_STATUS_CMD_TOUT; + else + return AVRISP_PROTO_STATUS_CMD_FAILED; +} + +AvrIspProto::AvrIspProto (AvrIsp &isp) + : isp_ (isp), sck_duration_us_ (1) +{ +} + +int +AvrIspProto::accept (uint8_t *data, int len) +{ + uint8_t r; + AvrIspProtoStatus status; + AvrIspResult isp_status; + uint16_t size; + /* Decode command. */ + switch (data[0]) + { + case AVRISP_PROTO_CMD_SIGN_ON: + if (len != 1) break; + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + data[2] = sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE); + memcpy (&data[3], UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE, + sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE)); + return 3 + sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE); + case AVRISP_PROTO_CMD_SET_PARAMETER: + if (len != 3) break; + status = AVRISP_PROTO_STATUS_CMD_OK; + switch (data[1]) + { + case AVRISP_PROTO_PARAM_SCK_DURATION: + sck_duration_us_ = std::max (data[2], static_cast (1)); + break; + case AVRISP_PROTO_PARAM_RESET_POLARITY: + if (data[2] != 1) + status = AVRISP_PROTO_STATUS_CMD_FAILED; + break; + default: + status = AVRISP_PROTO_STATUS_CMD_FAILED; + break; + } + data[1] = status; + return 2; + case AVRISP_PROTO_CMD_GET_PARAMETER: + if (len != 2) break; + status = AVRISP_PROTO_STATUS_CMD_OK; + switch (data[1]) + { + case AVRISP_PROTO_PARAM_SCK_DURATION: + data[2] = sck_duration_us_; + break; + case AVRISP_PROTO_PARAM_RESET_POLARITY: + data[2] = 1; + break; + case AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW: + data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 0); + break; + case AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH: + data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 1); + break; + case AVRISP_PROTO_PARAM_HW_VER: + data[2] = UCOO_CONFIG_DEV_AVRISP_PROTO_HW_VERSION; + break; + case AVRISP_PROTO_PARAM_SW_MAJOR: + data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 1); + break; + case AVRISP_PROTO_PARAM_SW_MINOR: + data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 0); + break; + default: + status = AVRISP_PROTO_STATUS_CMD_FAILED; + break; + } + data[1] = status; + return status == AVRISP_PROTO_STATUS_CMD_OK ? 3 : 2; + case AVRISP_PROTO_CMD_LOAD_ADDRESS: + if (len != 5) break; + isp_.load_address (bytes_pack (data[1], data[2], data[3], data[4])); + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + return 2; + case AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP: + if (len != 12) break; + isp_status = isp_.enter_progmode (sck_duration_us_, data[1], data[2], + data[3], data[4], data[5], data[6], + data[7], &data[8]); + data[1] = avrisp_proto_isp_status (isp_status); + return 2; + case AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP: + if (len != 3) break; + isp_.leave_progmode (data[1], data[2]); + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + return 2; + case AVRISP_PROTO_CMD_CHIP_ERASE_ISP: + if (len != 7) break; + isp_status = isp_.chip_erase (data[1], data[2], &data[3]); + data[1] = avrisp_proto_isp_status (isp_status); + return 2; + case AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP: + case AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP: + if (len < 10) break; + size = bytes_pack (data[1], data[2]); + if (len != 10 + size) break; + isp_status = isp_.program_begin (size, data[3], data[4], data[5], data[6], + data[7], &data[8], data[0] + == AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP); + if (isp_status == AVRISP_OK) + isp_status = isp_.program_continue (&data[10], size); + if (isp_status == AVRISP_OK) + isp_status = isp_.program_end (); + data[1] = avrisp_proto_isp_status (isp_status); + return 2; + case AVRISP_PROTO_CMD_READ_FLASH_ISP: + case AVRISP_PROTO_CMD_READ_EEPROM_ISP: + if (len != 4) break; + size = bytes_pack (data[1], data[2]); + isp_status = isp_.read_begin (size, data[3], data[0] + == AVRISP_PROTO_CMD_READ_FLASH_ISP); + if (isp_status == AVRISP_OK) + isp_status = isp_.read_continue (&data[2], size); + if (isp_status == AVRISP_OK) + isp_status = isp_.read_end (); + if (isp_status == AVRISP_OK) + { + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK; + return 2 + size + 1; + } + else + { + data[1] = AVRISP_PROTO_STATUS_CMD_FAILED; + return 2; + } + case AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP: + case AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP: + if (len != 5) break; + isp_.program_misc (&data[1]); + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + data[2] = AVRISP_PROTO_STATUS_CMD_OK; + return 3; + case AVRISP_PROTO_CMD_READ_FUSE_ISP: + case AVRISP_PROTO_CMD_READ_LOCK_ISP: + case AVRISP_PROTO_CMD_READ_SIGNATURE_ISP: + case AVRISP_PROTO_CMD_READ_OSCCAL_ISP: + if (len != 6) break; + r = isp_.read_misc (data[1], &data[2]); + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + data[2] = r; + data[3] = AVRISP_PROTO_STATUS_CMD_OK; + return 4; + case AVRISP_PROTO_CMD_SPI_MULTI: + if (len < 4) break; + size = data[2]; + if (len != 4 + size) break; + isp_.multi (data[1], data[2], data[3], &data[4], &data[2]); + data[1] = AVRISP_PROTO_STATUS_CMD_OK; + data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK; + return 2 + size + 1; + default: + /* Unknown. */ + data[1] = AVRISP_PROTO_STATUS_CMD_UNKNOWN; + return 2; + } + data[1] = AVRISP_PROTO_STATUS_CMD_FAILED; + return 2; +} + +} // namespace ucoo diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh new file mode 100644 index 00000000..2c09c092 --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh @@ -0,0 +1,50 @@ +#ifndef ucoolib_dev_avrisp_avrisp_proto_hh +#define ucoolib_dev_avrisp_avrisp_proto_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "avrisp.hh" + +namespace ucoo { + +/// Interpret commands in the AVR068 and AVR069 format. Framing is needed for +/// AVR068 and provided by AvrIspFrame. +class AvrIspProto +{ + public: + /// Constructor. + AvrIspProto (AvrIsp &isp); + /// Accept a frame to interpret. Return the response length provided in + /// the same buffer. The buffer should be large enough to store the + /// largest frame used by AVR06[89] protocol. + int accept (uint8_t *data, int len); + private: + /// Ref to ISP class. + AvrIsp &isp_; + /// SCK period. + uint8_t sck_duration_us_; +}; + +} // namespace ucoo + +#endif // ucoolib_dev_avrisp_avrisp_proto_hh diff --git a/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile b/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile new file mode 100644 index 00000000..80a83341 --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = stm32f4 +PROGS = test_avrisp +test_avrisp_SOURCES = test_avrisp.cc + +MODULES = dev/avrisp hal/spi hal/gpio base/test hal/usb utils + +include $(BASE)/build/top.mk diff --git a/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc b/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc new file mode 100644 index 00000000..66ecf14f --- /dev/null +++ b/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc @@ -0,0 +1,90 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 Nicolas Schodet +// +// APBTeam: +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// 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 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, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +#include "ucoolib/dev/avrisp/avrisp_frame.hh" + +#include "ucoolib/arch/arch.hh" +#include "ucoolib/base/test/test.hh" +#include "ucoolib/hal/gpio/gpio.hh" +#include "ucoolib/hal/spi/spi_soft.hh" +#include "ucoolib/utils/delay.hh" + +#include +#include + +class TestAvrIspIntf : public ucoo::AvrIspIntf +{ + public: + TestAvrIspIntf (ucoo::Io &reset, ucoo::Io &sck, ucoo::Io &mosi, + ucoo::Io &miso) + : reset_ (reset), sck_ (sck), spi_ (sck, mosi, miso) { } + uint8_t send_and_recv (uint8_t tx) + { + return spi_.send_and_recv (tx); + } + void enable (uint8_t sck_duration_us) + { + reset_.output (); + reset_.reset (); + sck_.output (); + sck_.reset (); + ucoo::delay_us (1000); + reset_.set (); + ucoo::delay_us (100); + reset_.reset (); + int freq = 1000000 / sck_duration_us; + spi_.setup (freq, ucoo::SPI_MODE_0); + } + void disable () + { + spi_.setup (0); + reset_.input (); + } + void sck_pulse () + { + sck_.toggle (); + ucoo::delay_us (100); + sck_.toggle (); + } + private: + ucoo::Io &reset_; + ucoo::Io &sck_; + ucoo::SpiSoftMaster spi_; +}; + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::Stream &ts = ucoo::test_stream (); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN + | RCC_AHB1ENR_IOPEEN); + ucoo::Gpio reset (GPIOD, 10), sck (GPIOE, 7), mosi (GPIOD, 8), + miso (GPIOD, 9); + TestAvrIspIntf intf (reset, sck, mosi, miso); + ucoo::AvrIsp isp (intf); + ucoo::AvrIspProto proto (isp); + ucoo::AvrIspFrame frame (proto); + while (1) + frame.read_and_write (ts); +} -- cgit v1.2.3