I got my daughter a new bicycle and purchased a bunch of the SpokePOV for her. It's been working great. But now I am trying to use bigger EEPROMs for more effects. I have been successfully using 8Kx8 and 16Kx8 eeproms, but the 32Kx8 is not detected correctly by the SpokePOV v1.4 program. I can program the 32Kx8 eeprom via other methods and it works correctly in the SpokePOV boards. So I know the 32Kx8 works. I just can't program them via the Window SpokePOV v1.4 program. I believe it has to do with the detection code in the SpokePOV v1.4 program. I would like to help troubleshoot the issue and would like to know if the Windows source code is available?
FYI, I am using this for the eeprom sources.
http://www.mouser.com/Semiconductors/Me ... c0&FS=True
SpokePOV v1.4 windows source code?
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
- hiduino
- Posts: 862
- Joined: Sat Sep 01, 2012 7:05 pm
Re: SpokePOV v1.4 windows source code?
Thanks @adafruit_support_rick!
I took a look at the code and found some issues with the eeprom detection routines and with the tiny2313 firmware. This issue prevents the use of 32Kx8 eeproms and also will cause missing pages with certain bit patterns in the eeprom. I noticed that several users in the past years have complained about loosing 2 pages of eeprom, so that the SpokePOV program only shows 2 pages instead of 4 pages.
Also I have some ideas of how to support upto 64Kx8 eeproms with minimal changes.
The only issue is I don't think I have the environment to re-build the SpokePOV for Windows or Mac. However, I do have the resources to re-build the tiny2313 firmware. I'll be glad to share my findings in a later post.
I took a look at the code and found some issues with the eeprom detection routines and with the tiny2313 firmware. This issue prevents the use of 32Kx8 eeproms and also will cause missing pages with certain bit patterns in the eeprom. I noticed that several users in the past years have complained about loosing 2 pages of eeprom, so that the SpokePOV program only shows 2 pages instead of 4 pages.
Also I have some ideas of how to support upto 64Kx8 eeproms with minimal changes.
The only issue is I don't think I have the environment to re-build the SpokePOV for Windows or Mac. However, I do have the resources to re-build the tiny2313 firmware. I'll be glad to share my findings in a later post.
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
Re: SpokePOV v1.4 windows source code?
Thanks! We'll look forward to your report!
- hiduino
- Posts: 862
- Joined: Sat Sep 01, 2012 7:05 pm
Re: SpokePOV v1.4 windows source code?
There are a few issues with the current wxSpokePOV program and the t2313 firmware.
1) The EEPROM size detection routine has a bug where certain memory patterns in the eeprom will fool the detection routine to end early and report only 2 pages of eeprom instead of 4 or more depending on the size of the eeprom. This is a rare case but it has happened to a number of users reported here in the forum over the years.
2) 32Kx8 does not get detected properly. This is partly the detection routine and how the tiny2313 firmware chooses between the t2313 internal eeprom vs. the external eeprom to read/write from. (I'll split this to a separate post.)
So first, the original eeprom size detection routine in the SpokePOVFrame::Connect() code is using a method of memory address wrap around to detect the size.
Original code from SpokePOVFrame::Connect():This first section of this code is reading past each of the eeprom sizes boundry, 1K, 2K, 4K, 8K, 16K, and 32K to where it wraps around back to memory location 0 to compare against.
However, in a later part it incorrectly uses byte[0] as memory location 0. This is actually location 0x400 on eeproms 2K and larger. This is where it fails to match the correct location and cause false detection sizes.
This part appears to be just dead code that really doesn't do anything:
The updated code here fixes the corruption/detection issues and also allows for 64Kx8 eeprom sizes. Also is backwards compatible with old and new attiny2313 firmwares.
Also changing the spokepov.h for 64 pages max.
1) The EEPROM size detection routine has a bug where certain memory patterns in the eeprom will fool the detection routine to end early and report only 2 pages of eeprom instead of 4 or more depending on the size of the eeprom. This is a rare case but it has happened to a number of users reported here in the forum over the years.
2) 32Kx8 does not get detected properly. This is partly the detection routine and how the tiny2313 firmware chooses between the t2313 internal eeprom vs. the external eeprom to read/write from. (I'll split this to a separate post.)
So first, the original eeprom size detection routine in the SpokePOVFrame::Connect() code is using a method of memory address wrap around to detect the size.
Original code from SpokePOVFrame::Connect():
Code: Select all
unsigned char byte[6];
/*
#if defined (WIN32_NATIVE)
for (int delay=1; delay <=5; delay++) {
#else
for (int delay=4; delay <=6; delay++) {
#endif
*/
comm->reset(); // reset
wxMilliSleep(1000);
comm->delay = comm_delay;
/*if (comm->readbyte(0, &byte1))
break;
wxLogDebug("trying longer delay %d", delay+1);
}*/
// check up to 32KB
for (int i = 0; i<6; i++) {
if (!comm->readbyte((1<<i)*1024, &byte[i]))
return -1;
}
wxLogDebug("%d %d %d %d %d %d", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5] );
banks = 0;
// is this a 1x memory?
for (int j=0; j<6; j++) {
wxLogDebug("test for %d banks", 1<<j);
for (int i=j; i<6; i++) {
if (byte[i] != byte[0])
break;
}
// possibly!
comm->writebyte(0, ~byte[0]); // invert one byte
if (!comm->readbyte(1024*(1<<j), &ret)) {
return -1;
}
if (ret == ((unsigned char)(~byte[0]))) {
banks = 1<<j; // yes!
break;
} else {
wxLogDebug("0x%02x 0x%02x", ret, (unsigned char)~byte[0]);
}
if (!comm->writebyte(0, byte[0])) {
return -1;
}
}
wxLogDebug("found %d banks of memory", banks);
Code: Select all
// check up to 32KB
for (int i = 0; i<6; i++) {
if (!comm->readbyte((1<<i)*1024, &byte[i]))
return -1;
}
Code: Select all
comm->writebyte(0, ~byte[0]); // invert one byte
if (!comm->readbyte(1024*(1<<j), &ret)) {
return -1;
}
if (ret == ((unsigned char)(~byte[0]))) {
banks = 1<<j; // yes!
break;
} else {
Code: Select all
for (int i=j; i<6; i++) {
if (byte[i] != byte[0])
break;
}
Code: Select all
comm->reset(); // reset
wxMilliSleep(1000);
comm->delay = comm_delay;
unsigned char byte[7],mem4;
// Save memory 0x04
if (!comm->readbyte(0x04, &mem4)) {
return -1;
}
// check up to 64KB
for (int i = 0; i<7; i++) {
if (!comm->readbyte((1<<i)*1024+0x04, &byte[i]))
return -1;
}
wxLogDebug("%d %d %d %d %d %d %d", byte[0], byte[1], byte[2], byte[3], byte[4], byte[5], byte[6] );
banks = 0;
comm->writebyte(0x04, (unsigned char)~mem4); // invert memory 0x04
// is this a 1x memory?
for (int j=0; j<7; j++) {
wxLogDebug("test for %d banks", 1<<j);
if (byte[j] == mem4) {
// possibly!
if (!comm->readbyte((1<<j)*1024+0x04, &ret)) {
return -1;
}
if (ret == (unsigned char)~mem4) {
banks = 1<<j; // yes!
break;
} else { // nope!
wxLogDebug("0x%02x 0x%02x", ret, (unsigned char)~byte[0]);
}
}
}
if (!comm->writebyte(0x04, mem4)) { // restore memory 0x04
return -1;
}
wxLogDebug("found %d banks of memory", banks);
Code: Select all
#define MAX_BANKS 64
Last edited by hiduino on Fri Jul 10, 2015 11:43 pm, edited 6 times in total.
- hiduino
- Posts: 862
- Joined: Sat Sep 01, 2012 7:05 pm
Re: SpokePOV v1.4 windows source code?
Continuing from previous post.
The detection routine relies on the passing memory location 0x8000 to read from for the 32Kx8 eeprom. It expect the eeprom will ignore the high bit and read from memory location 0x0. However, the t2313 firmware is mapping the internal eeprom to those locations 0x8000 - 0x8002 for the rotation offset, mirror, and animation time variables. So the firmware never allows for proper 32Kx8 eeprom detection.
Original tiny2313 firmware code v1.01:
The fix is to test external memory locations outside of the t2313 internal 0x8000 - 0x8002 locations. Also to only do this for single byte read/writes. This will never overlap with the detection routine or with normal external eeprom 16 byte read/writes.
I have tested these fixes for the wxSpokePOV software and the tiny2313 firmware with EEPROM from 4Kx8, 8Kx8, 16Kx8, 32Kx8 and 64Kx8 sizes successfully.
(BTW, I was able to build wxSpokePOV under Windows with MinGW/msys and wxWidgets-2.8.1.)
For those who want to try: I would attach the Windows spokepov.exe file but it was a little too large.
The detection routine relies on the passing memory location 0x8000 to read from for the 32Kx8 eeprom. It expect the eeprom will ignore the high bit and read from memory location 0x0. However, the t2313 firmware is mapping the internal eeprom to those locations 0x8000 - 0x8002 for the rotation offset, mirror, and animation time variables. So the firmware never allows for proper 32Kx8 eeprom detection.
Original tiny2313 firmware code v1.01:
Code: Select all
switch (cmd) {
case COMP_CMD_RDEEPROM:
case COMP_CMD_RDEEPROM16:
if (cmd == COMP_CMD_RDEEPROM16)
n = 16;
else
n = 1;
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
if ((addr & 0x8000) != 0) {
tx_computer_byte(internal_eeprom_read(addr & 0xFF));
} else {
spieeprom_read(addr, buff, n);
for (i=0; i<n; i++) {
tx_computer_byte(buff[i]);
}
}
tx_computer_byte(COMP_SUCCESS);
break;
case COMP_CMD_WREEPROM:
case COMP_CMD_WREEPROM16:
if (cmd == COMP_CMD_WREEPROM16)
n = 16;
else
n = 1;
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
set_led((addr/16)%32,FRONT);
for (i=0; i<n; i++) {
buff[i] = tx_computer_byte(0);
}
tx_computer_byte(COMP_SUCCESS);
if ((addr & 0x8000) != 0) {
internal_eeprom_write(addr & 0xFF, buff[0]);
} else {
spieeprom_write(addr, buff, n);
}
break;
}
Code: Select all
switch (cmd) {
case COMP_CMD_RDEEPROM:
case COMP_CMD_RDEEPROM16:
if (cmd == COMP_CMD_RDEEPROM16)
n = 16;
else
n = 1;
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
if (((addr & 0xFFFC) == 0x8000) && (n == 1)) {
tx_computer_byte(internal_eeprom_read(addr & 0xFF));
} else {
spieeprom_read(addr, buff, n);
for (i=0; i<n; i++) {
tx_computer_byte(buff[i]);
}
}
tx_computer_byte(COMP_SUCCESS);
break;
case COMP_CMD_WREEPROM:
case COMP_CMD_WREEPROM16:
if (cmd == COMP_CMD_WREEPROM16)
n = 16;
else
n = 1;
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
set_led((addr/16)%32,FRONT);
for (i=0; i<n; i++) {
buff[i] = tx_computer_byte(0);
}
tx_computer_byte(COMP_SUCCESS);
if (((addr & 0xFFFC) == 0x8000) && (n == 1)) {
internal_eeprom_write(addr & 0xFF, buff[0]);
} else {
spieeprom_write(addr, buff, n);
}
break;
}
}
(BTW, I was able to build wxSpokePOV under Windows with MinGW/msys and wxWidgets-2.8.1.)
For those who want to try: I would attach the Windows spokepov.exe file but it was a little too large.
Last edited by hiduino on Thu Jul 09, 2015 11:21 pm, edited 6 times in total.
- hiduino
- Posts: 862
- Joined: Sat Sep 01, 2012 7:05 pm
Re: SpokePOV v1.4 windows source code?
I should note that i have updated wxSpokePOV program above in addition to the eeprom corruption/detection fix and 64Kx8 support, is backwards compatible with the original tiny2313 firmware v1.01. I also updated the attiny2313 firmware so that it is also backward compatible with the older wxSpokePOV program. The firmware update is needed only if you want to use 32Kx8 and 64Kx8 eeproms.
Note: To support the backawards compatibility I reverted back to the original tiny2313 internal EEPROM memory mapped addresses in the global.h file:
Note: To support the backawards compatibility I reverted back to the original tiny2313 internal EEPROM memory mapped addresses in the global.h file:
Code: Select all
#define EEPROM_ROTOFFSET 0x8000
#define EEPROM_MIRROR 0x8001
#define EEPROM_ANIMTIME 0x8002
- hiduino
- Posts: 862
- Joined: Sat Sep 01, 2012 7:05 pm
Re: SpokePOV v1.4 windows source code?
I was having failures with the Verify SpokePOV feature and found another potentially serious bug with wxSpokePOV v1.4 code. It has to do with reading/writing to eeprom banks from/to the wheel panel model[][] array for comparisons.
The model[256][30] array is created with 256 rows by 30 leds. However in the WheelPanel::GetModel() and WheelPanel::SetModel() functions they are trying to access 32 leds, which is out of bounds. This potentially could cause memory corruption on the Computer system.
From wheelplanel.cpp, the "led" index will range from 0 to 31:
I updated the code to do a bounds checking so "led" index should only range from 0 to 29:
The model[256][30] array is created with 256 rows by 30 leds. However in the WheelPanel::GetModel() and WheelPanel::SetModel() functions they are trying to access 32 leds, which is out of bounds. This potentially could cause memory corruption on the Computer system.
From wheelplanel.cpp, the "led" index will range from 0 to 31:
Code: Select all
bool WheelPanel::GetModel(unsigned char buff[]) {
int t;
for (int i=0; i<ROWS_PER_WHEEL; i++) {
for (int j = 0; j<4; j++) {
t = 0;
for (int k=0; k<8; k++) {
t <<= 1;
if (! model[i][j*8+k]) {
t |= 0x1;
}
}
buff[i*4+j] = t;
}
}
return true;
}
bool WheelPanel::SetModel(unsigned char buff[1024]) {
int row, led;
for (int i=0; i<1024; i++) {
row = i/4;
for (int j = 0; j<8; j++) {
led = (i%4)*8+j;
if (buff[i] & (1<<(7-j)))
model[row][led] = false;
else
model[row][led] = true;
}
}
Refresh();
return true;
}
Code: Select all
bool WheelPanel::GetModel(unsigned char buff[]) {
int t;
for (int i=0; i<ROWS_PER_WHEEL; i++) {
for (int j = 0; j<4; j++) {
t = 0;
for (int k=0; k<8; k++) {
t <<= 1;
if (j*8+k < num_leds) { // bounds checking
if (! model[i][j*8+k]) {
t |= 0x1;
}
} else {
t |= 0x01; // default unused bits to off, for verification checks.
}
}
buff[i*4+j] = t;
}
}
return true;
}
bool WheelPanel::SetModel(unsigned char buff[1024]) {
int row, led;
for (int i=0; i<1024; i++) {
row = i/4;
for (int j = 0; j<8; j++) {
led = (i%4)*8+j;
if (led < num_leds) { // bounds checking
if (buff[i] & (1<<(7-j)))
model[row][led] = false;
else
model[row][led] = true;
}
}
}
Refresh();
return true;
}
Please be positive and constructive with your questions and comments.