mirror of https://github.com/arendst/Tasmota.git
670 lines
17 KiB
C++
670 lines
17 KiB
C++
#include "c2.h"
|
|
|
|
/////////////////////////////////////////////
|
|
// Nothing should need change on this file //
|
|
/////////////////////////////////////////////
|
|
|
|
// Times in microseconds
|
|
#define T_RD (20+5)
|
|
#define T_SD ( 2+5)
|
|
|
|
// Layer 0: Bit shifter
|
|
static bool c2_bit(bool b) {
|
|
C2D(b);
|
|
// C2_DELAY_US(1);
|
|
C2CK(0);
|
|
// C2_DELAY_US(1);
|
|
b = C2D();
|
|
C2CK(1);
|
|
return b;
|
|
}
|
|
|
|
// Layer 1: C2D Register read/write
|
|
void c2_address_write(uint8_t address) {
|
|
#ifdef C2_DEBUG
|
|
Serial.print("AW");
|
|
Serial.println(address, HEX);
|
|
#endif
|
|
// start
|
|
c2_bit(true);
|
|
C2D_enable(true);
|
|
|
|
// instruction
|
|
c2_bit(1);
|
|
c2_bit(1);
|
|
|
|
// Address
|
|
for (int i = 0; i < 8; ++i) {
|
|
c2_bit(address & 1);
|
|
address >>= 1;
|
|
}
|
|
|
|
// Stop
|
|
C2D_enable(false);
|
|
c2_bit(1);
|
|
}
|
|
|
|
uint8_t c2_address_read() {
|
|
// start
|
|
c2_bit(true);
|
|
C2D_enable(true);
|
|
|
|
// instruction
|
|
c2_bit(0);
|
|
c2_bit(1);
|
|
|
|
// Change C2D direction
|
|
C2D_enable(false);
|
|
c2_bit(0);
|
|
|
|
// Address
|
|
uint8_t a = 0, m = 1;
|
|
for (int i = 0; i < 8; ++i) {
|
|
if (c2_bit(a & 1)) {
|
|
a |= m;
|
|
}
|
|
m <<= 1;
|
|
}
|
|
|
|
// Stop is implied
|
|
#ifdef C2_DEBUG
|
|
Serial.print("AR");
|
|
Serial.println(a, HEX);
|
|
#endif
|
|
return a;
|
|
}
|
|
|
|
uint8_t c2_data_write(uint32_t d, uint8_t bytes) {
|
|
#ifdef C2_DEBUG
|
|
Serial.print("DW");
|
|
Serial.println(d, HEX);
|
|
#endif
|
|
|
|
// start
|
|
c2_bit(true);
|
|
C2D_enable(true);
|
|
|
|
// instruction
|
|
c2_bit(1);
|
|
c2_bit(0);
|
|
|
|
// Length
|
|
bytes--;
|
|
c2_bit(bytes & 1);
|
|
c2_bit(bytes & 2);
|
|
bytes++;
|
|
|
|
// Data
|
|
for (int i = 0; i < 8 * bytes; ++i) {
|
|
c2_bit(d & 1);
|
|
d >>= 1;
|
|
}
|
|
|
|
// Reverse C2D direction
|
|
C2D_enable(false);
|
|
c2_bit(0);
|
|
|
|
// Wait
|
|
uint8_t to = 128;
|
|
while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT;
|
|
|
|
// Stop
|
|
//c2_bit(0); implied
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_data_read(uint32_t &d, uint8_t bytes) {
|
|
// start
|
|
c2_bit(true);
|
|
C2D_enable(true);
|
|
|
|
// instruction
|
|
c2_bit(0);
|
|
c2_bit(0);
|
|
|
|
// Length
|
|
bytes--;
|
|
c2_bit(bytes & 1);
|
|
c2_bit(bytes & 2);
|
|
bytes++;
|
|
|
|
// Reverse C2D direction
|
|
C2D_enable(false);
|
|
c2_bit(0);
|
|
|
|
// Wait
|
|
uint8_t to = 128;
|
|
while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT;
|
|
|
|
// Data
|
|
d = 0;
|
|
uint32_t m = 1;
|
|
for (int i = 0; i < 8 * bytes; ++i) {
|
|
if (c2_bit(d & 1)) {
|
|
d |= m;
|
|
}
|
|
m <<= 1;
|
|
}
|
|
|
|
// Stop is implied
|
|
#ifdef C2D_DEBUG
|
|
Serial.print("DR");
|
|
Serial.println(d, HEX);
|
|
#endif
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
// Layer 2: Operations
|
|
#define C2_POLL_INBUSY() { \
|
|
uint16_t to = 1000; \
|
|
uint8_t a; \
|
|
while (1) { \
|
|
a = c2_address_read(); \
|
|
if (a == 0xFF) return C2_BROKEN_LINK; \
|
|
if (~a & C2_INBUSY) break; \
|
|
if (--to == 0) return C2_POLL_TIMEOUT; \
|
|
C2_DELAY_MS(1); \
|
|
}; \
|
|
}
|
|
|
|
#define C2_POLL_OUTREADY() { \
|
|
uint16_t to = 10000; \
|
|
uint8_t a; \
|
|
while (1) { \
|
|
a = c2_address_read(); \
|
|
if (a == 0xFF) return C2_BROKEN_LINK; \
|
|
if (a & C2_OUTREADY) break; \
|
|
if (--to == 0) return C2_POLL_TIMEOUT; \
|
|
C2_DELAY_MS(1); \
|
|
}; \
|
|
}
|
|
|
|
#define C2_DATA_WRITE_AND_CHECK(v, s) { \
|
|
uint8_t r = c2_data_write(v, s); \
|
|
if (r != C2_SUCCESS) return r; \
|
|
}
|
|
|
|
#define C2_DATA_READ_AND_CHECK(v, s) { \
|
|
uint8_t r = c2_data_read(v, s); \
|
|
if (r != C2_SUCCESS) return r; \
|
|
}
|
|
|
|
#define C2_EXPECT_DATA(value) { \
|
|
uint8_t d; \
|
|
C2_DATA_READ_AND_CHECK(d, 1); \
|
|
if (d != (value)) return C2_CMD_ERROR; \
|
|
}
|
|
|
|
uint8_t c2_reset() {
|
|
C2CK(false);
|
|
C2_DELAY_US(T_RD);
|
|
C2CK(true);
|
|
C2_DELAY_US(T_SD);
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_programming_init(uint8_t devid) {
|
|
c2_reset();
|
|
c2_address_write(C2FPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE0, 1);
|
|
C2_DATA_WRITE_AND_CHECK(C2FPCTL_CORE_HALT, 1);
|
|
C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE1, 1)
|
|
C2_DELAY_MS(21);
|
|
|
|
// device specific initialization, see https://www.silabs.com/documents/public/application-notes/AN127.pdf
|
|
switch (devid) {
|
|
case C2_DEVID_UNKNOWN:
|
|
break;
|
|
case C2_DEVID_EFM8BB1:
|
|
case C2_DEVID_EFM8BB2:
|
|
case C2_DEVID_EFM8BB3: // C2_DEVID_EFM8LB1 is the same
|
|
c2_address_write(0xFF);
|
|
C2_DATA_WRITE_AND_CHECK(0x80, 1);
|
|
C2_DELAY_US(5);
|
|
c2_address_write(0xEF);
|
|
C2_DATA_WRITE_AND_CHECK(0x02, 1);
|
|
c2_address_write(0xA9);
|
|
C2_DATA_WRITE_AND_CHECK(0x00, 1);
|
|
break;
|
|
default:
|
|
return C2_BROKEN_LINK;
|
|
}
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_block_write(uint32_t address, uint8_t *data, uint8_t len) {
|
|
// 1. Perform an Address Write with a value of FPDAT
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Perform a Data Write with the Block Write command.
|
|
C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_WRITE, 1);
|
|
|
|
// 3. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with the high byte of the address.
|
|
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
|
|
|
|
// 7. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Perform a Data Write with the low byte of the address.
|
|
C2_DATA_WRITE_AND_CHECK(address & 255, 1);
|
|
|
|
// 9. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 10. Perform a Data Write with the length.
|
|
C2_DATA_WRITE_AND_CHECK(len, 1);
|
|
|
|
// 12a. Repeat steps 11 and 12 for each byte specified by the length field.
|
|
uint8_t i = 0;
|
|
do {
|
|
// 11. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 12. Perform a Data Write with the data. This will write the data to the flash.
|
|
C2_DATA_WRITE_AND_CHECK(data[i], 1);
|
|
} while (++i != len);
|
|
|
|
// 13. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 14. Perform a Data Read instruction. A value of 0x0D is okay. write to an EPROM block:
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_eeprom_write(uint32_t address, uint8_t *data, uint8_t len) {
|
|
// 1. Write 0x04 to the FPCTL register.
|
|
c2_address_write(C2FPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x04, 1);
|
|
|
|
// 2. Write 0x40 to EPCTL.
|
|
c2_address_write(C2EPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x40, 1);
|
|
|
|
// 3. Write 0x58 to EPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x58, 1);
|
|
|
|
// 4. Write the high byte of the address to EPADDRH.
|
|
c2_address_write(C2EPADDRH);
|
|
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
|
|
|
|
// 5. Write the low byte of the address to address EPADDRL.
|
|
c2_address_write(C2EPADDRL);
|
|
C2_DATA_WRITE_AND_CHECK(address, 1);
|
|
|
|
// 6. Perform an Address Write with a value of EPDAT.
|
|
c2_address_write(C2EPDAT);
|
|
|
|
// 7. Turn on VPP.
|
|
|
|
// 8. Wait for the VPP settling time.
|
|
|
|
// 10a. Repeat steps 9 and 10 until all bytes are written.
|
|
uint8_t i = 0;
|
|
do {
|
|
// 9. Write the data to the device using a Data Write.
|
|
C2_DATA_WRITE_AND_CHECK(data[i], 1);
|
|
|
|
// 10. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy.
|
|
C2_POLL_INBUSY();
|
|
} while (++i != len);
|
|
|
|
// 12. Turn off VPP. Note that VPP can only be applied for a maximum lifetime amount, and this value is specified in the device data sheet.
|
|
|
|
// 13. Write 0x40 to EPCTL.
|
|
c2_address_write(C2EPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x40, 1);
|
|
|
|
// 14. Write 0x00 to EPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x00, 1);
|
|
|
|
// 15. Write 0x02 to FPCTL.
|
|
c2_address_write(C2FPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x02, 1);
|
|
|
|
// 16. Write 0x04 to FPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x04, 1);
|
|
|
|
// 17. Write 0x01 to FPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x01, 1);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_block_read(uint32_t address, uint8_t *data, uint8_t len) {
|
|
// 1. Perform an Address Write with a value of FPDAT.
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Perform a Data Write with the Block Read command.
|
|
C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_READ, 1);
|
|
|
|
// 3. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with the high byte of the address.
|
|
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
|
|
|
|
// 7. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Perform a Data Write with the low byte of the address.
|
|
C2_DATA_WRITE_AND_CHECK(address, 1);
|
|
|
|
// 9. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 10. Perform a Data Write with the length.
|
|
C2_DATA_WRITE_AND_CHECK(len, 1);
|
|
|
|
// 11. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 12. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 13. Read FPI Command Status. Abort if Status != 0x0D.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 15a. Repeat step 14 and 15 for each byte specified by the length field.
|
|
uint8_t i = 0;
|
|
do {
|
|
// 14. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 15. Perform a Data Read instruction. This will read the data from the flash.
|
|
C2_DATA_READ_AND_CHECK(data[i], 1);
|
|
} while (++i != len);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_eeprom_read(uint32_t address, uint8_t *data, uint8_t len) {
|
|
// 1. Write 0x04 to the FPCTL register.
|
|
c2_address_write(C2FPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x04, 1);
|
|
|
|
// 2. Write 0x00 to EPCTL.
|
|
c2_address_write(C2EPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x00, 1);
|
|
|
|
// 3. Write 0x58 to EPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x58, 1);
|
|
|
|
// 4. Write the high byte of the address to EPADDRH.
|
|
c2_address_write(C2EPADDRH);
|
|
C2_DATA_WRITE_AND_CHECK(address >> 8, 1);
|
|
|
|
// 5. Write the low byte of the address to address EPADDRL.
|
|
c2_address_write(C2EPADDRL);
|
|
C2_DATA_WRITE_AND_CHECK(address, 1);
|
|
|
|
// 6. Perform an Address Write with a value of EPDAT.
|
|
c2_address_write(C2EPDAT);
|
|
|
|
// 9. Repeat steps 7 and 8 until all bytes are read.
|
|
uint8_t i = 0;
|
|
do {
|
|
// 7.1. Perform an Address Write operation with a value of EPSTAT.
|
|
c2_address_write(C2EPSTAT);
|
|
|
|
// 7.2. Perform a Data Read operation and check the bits of the EPSTAT register.
|
|
uint8_t err;
|
|
C2_DATA_READ_AND_CHECK(err, 1);
|
|
if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR;
|
|
|
|
// 7.3. Perform an Address Write operation with a value of EPDAT.
|
|
c2_address_write(C2EPDAT);
|
|
|
|
// 7. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8.1. Perform an Address Write operation with a value of EPSTAT.
|
|
c2_address_write(C2EPSTAT);
|
|
|
|
// 8.2. Perform a Data Read operation and check the ERROR bit in the EPSTAT register.
|
|
C2_DATA_READ_AND_CHECK(err, 1);
|
|
if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR;
|
|
|
|
// 8.3. Perform an Address Write operation with a value of EPDAT.
|
|
C2_DATA_WRITE_AND_CHECK(C2EPDAT, 1);
|
|
|
|
// 8. Read the byte using the Data Read instruction.
|
|
C2_DATA_READ_AND_CHECK(data[i], 1);
|
|
} while (++i != len);
|
|
|
|
// 10. Write 0x40 to EPCTL.
|
|
c2_address_write(C2EPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x40, 1);
|
|
|
|
// 11. Write 0x00 to EPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x00, 1);
|
|
|
|
// 12. Write 0x02 to FPCTL.
|
|
c2_address_write(C2FPCTL);
|
|
C2_DATA_WRITE_AND_CHECK(0x02, 1);
|
|
|
|
// 13. Write 0x04 to FPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x04, 1);
|
|
|
|
// 14. Write 0x01 to FPCTL.
|
|
C2_DATA_WRITE_AND_CHECK(0x01, 1);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_page_erase(uint8_t page) {
|
|
// 1. Perform an Address Write with a value of FPDAT.
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Perform a Data Write with the Page Erase command.
|
|
c2_data_write(C2FPDAT_FLASH_PAGE_ERASE, 1);
|
|
|
|
// 3. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with the page number.
|
|
c2_data_write(page, 1);
|
|
|
|
// 7. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Poll on OutReady using Address Read until the bit clears.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 9. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 10. Perform a Data Write with the a value of 0x00.
|
|
c2_data_write(0x00, 1);
|
|
|
|
// 11. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 12. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 13. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_device_erase() {
|
|
// 1. Perform an Address Write with a value of FPDAT.
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Perform a Data Write with the Device Erase command.
|
|
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DEVICE_ERASE, 1);
|
|
|
|
// 3. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with a value of 0xDE.
|
|
C2_DATA_WRITE_AND_CHECK(0xDE, 1);
|
|
|
|
// 7. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Perform a Data Write with a value of 0xAD.
|
|
C2_DATA_WRITE_AND_CHECK(0xAD, 1);
|
|
|
|
// 9. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 10. Perform a Data Write with a value of 0xA5.
|
|
C2_DATA_WRITE_AND_CHECK(0xA5, 1);
|
|
|
|
// 11. Poll on InBusy using Address Read until the bit clears.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 12. Poll on OutReady using Address Read until the bit set.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 13. Perform a Data Read instruction. A value of 0x0D is okay.
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_sfr_write_non_paged(uint8_t address, uint8_t data) {
|
|
// 1. Write the SFR address to the device using the Address Write instruction.
|
|
c2_address_write(address);
|
|
|
|
// 2. Write the SFR value to the device using the Data Write instruction.
|
|
C2_DATA_WRITE_AND_CHECK(data, 1);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
uint8_t c2_sfr_write_paged(uint8_t address, uint8_t data) {
|
|
// 1. Perform an Address Write with a value of FPDAT.
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Write the Direct Write command (0x0A) using a Data Write
|
|
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_WRITE, 1);
|
|
|
|
// 3. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll OutReady it sets to 1.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read to ensure a return value of 0x0D (no errors).
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with a value of the SFR address.
|
|
C2_DATA_WRITE_AND_CHECK(address, 1);
|
|
|
|
// 7. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Perform a Data Write with a value of 0x01.
|
|
C2_DATA_WRITE_AND_CHECK(0x01, 1);
|
|
|
|
// 9. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 10. Perform a Data Write with the new SFR value.
|
|
C2_DATA_WRITE_AND_CHECK(data, 1);
|
|
|
|
// 11. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
// 4.6. Reading from an SFR
|
|
// To read from an SFR on a device that does not have SFR paging:
|
|
uint8_t c2_sfr_read_non_paged(uint8_t address, uint8_t &v) {
|
|
// 1. Write the SFR address to the device using the Address Write instruction.
|
|
c2_address_write(address);
|
|
|
|
// 2. Read the SFR value from the device using the Data Read instruction.
|
|
C2_DATA_READ_AND_CHECK(v, 1);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
// For devices with SFR paging, direct reads through the PI using the Direct Read command are recommended to ensure the SFR Page is managed properly.
|
|
// To read an SFR from a device with SFR paging:
|
|
uint8_t c2_sfr_read_paged(uint8_t address, uint8_t &v) {
|
|
// 1. Perform an Address Write with a value of FPDAT.
|
|
c2_address_write(C2FPDAT);
|
|
|
|
// 2. Write the Direct Read command (0x09) using a Data Write.
|
|
C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_READ, 1);
|
|
|
|
// 3. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 4. Poll OutReady until it sets to 1.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 5. Perform a Data Read to ensure a return value of 0x0D (no errors).
|
|
C2_EXPECT_DATA(0x0D);
|
|
|
|
// 6. Perform a Data Write with a value of the SFR address.
|
|
C2_DATA_WRITE_AND_CHECK(address, 1);
|
|
|
|
// 7. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 8. Perform a Data Write with a value of 0x01.
|
|
C2_DATA_WRITE_AND_CHECK(0x01, 1);
|
|
|
|
// 9. Poll InBusy until the data is processed by the PI.
|
|
C2_POLL_INBUSY();
|
|
|
|
// 10. Poll OutReady until it sets to 0.
|
|
C2_POLL_OUTREADY();
|
|
|
|
// 11. Read the SFR value from the device using the Data Read instruction.
|
|
C2_DATA_READ_AND_CHECK(v, 1);
|
|
|
|
return C2_SUCCESS;
|
|
}
|
|
|
|
const char *c2_print_status_by_name(uint8_t ch) {
|
|
switch (ch) {
|
|
case C2_SUCCESS: return "Success";
|
|
case C2_SHIFT_TIMEOUT: return "Shift wait timeout error";
|
|
case C2_POLL_TIMEOUT: return "Register poll timeout error";
|
|
case C2_CMD_ERROR: return "In-command error";
|
|
case C2_BROKEN_LINK: return "Broken link, address read failed";
|
|
default: return "unknownl error";
|
|
}
|
|
}
|
|
|
|
// This is to enforce arduino-like formatting in kate
|
|
// kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
|