}
#endif
#if defined(__AVR_ATmega328P__)
- if (ADCH < 0xd0 && ADCH >= 0xc0) {
+ if (ADCH < 0xd8 && ADCH >= 0xc0) {
hardwareVersion = 1;
- } else if (ADCH < 0xd0 && ADCH >= 0xb0) {
+ } else if (ADCH < 0xd8 && ADCH >= 0xb0) {
hardwareVersion = 2;
}
#endif
if (hardwareVersion == 0) {
#ifdef __AVR_ATmega644P__
- printf("Invalid Hardware-Version: ADC7H = %d (ATmega644P, 3.3V)\n", ADCH);
+ printf("\nInvalid Hardware-Version: ADC7H = %d (ATmega644P, 3.3V)\n", ADCH);
#elif __AVR_ATmega1284P__
- printf("Invalid Hardware-Version: ADC7H = %d (ATmega1284P, 3.3V)\n", ADCH);
+ printf("\nInvalid Hardware-Version: ADC7H = %d (ATmega1284P, 3.3V)\n", ADCH);
#elif __AVR_ATmega328P__
- printf("Invalid Hardware-Version: ADC7H = %d (ATmega328P, 5V)\n", ADCH);
+ printf("\nInvalid Hardware-Version: ADC7H = %d (ATmega328P, 5V)\n", ADCH);
#endif
}
#ifdef __AVR_ATmega328P__
TestUnit *unit[] = {
- &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &lcd,
+ &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd,
&i2cMaster, &i2cSlave, &i2cSparkfun
};
#endif
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
- // Nano-644
+ // Nano-644 / Nano1284
// --------------------------------------------------------
// PA7 ... nCS
// PB5 ... MOSI
// PORTB/DDRB must be configured before SPCR !!
PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!!
DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5)
+ DDRB &= ~(1 << PB6);
- // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz
- SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+ SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz
+ // SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
}
void PortExp::cleanup () {
PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!!
DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2)
- // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz
- SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+ SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz
+ // SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+
+ if (hardwareVersion == 2) {
+ PORTD |= (1 << PD7); // nCS when V2a/JP39.2-3 jumpered
+ DDRD |= (1 << PD7);
+ }
}
void PortExp::cleanup () {
}
void PortExp::setChipEnable () {
- PORTC &= ~(1 << PC1);
+ if (hardwareVersion == 2) {
+ PORTD &= ~(1 << PD7);
+ }
}
void PortExp::clearChipEnable () {
- PORTC |= (1 << PC1);
+ if (hardwareVersion == 2) {
+ PORTD |= (1 << PD7);
+ }
}
#endif
int8_t PortExp::writeByte (uint8_t addr, uint8_t b) {
-
+ // no response via SPI MISO because SO stays tristate on write cycle
setChipEnable();
-
SPDR = 0x40; // WRITE BYTE
while ((SPSR & (1 << SPIF)) == 0) {}
- if (SPDR != 0) {
- printf_P(PSTR("E1"));
- clearChipEnable();
- return -1;
- }
-
SPDR = addr; // register address
while ((SPSR & (1 << SPIF)) == 0) {}
- if (SPDR != 0) {
- printf_P(PSTR("E2"));
- clearChipEnable();
- return -1;
- }
-
SPDR = b; // value
while ((SPSR & (1 << SPIF)) == 0) {}
- if (SPDR != 0) {
- printf_P(PSTR("E3"));
- clearChipEnable();
- return -1;
- }
-
clearChipEnable();
_delay_us(5);
return 0;
}
+uint8_t PortExp::readByte (uint8_t addr) {
+ // response via SPI MISO only on third byte
+ setChipEnable();
+ SPDR = 0x41; // write "READ BYTE"
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ SPDR = addr; // write "register address"
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ SPDR = 0; // additional 8 clocks to get response from port expander
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ clearChipEnable();
+ return SPDR;
+}
+
+void PortExp::checkResponse (uint8_t address, uint8_t response, uint8_t desired) {
+ printf_P(PSTR(" (read 0x%02x -> 0x%02x"), address, response);
+ if (response != desired) {
+ printf_P(PSTR(" ERROR"));
+ if (response == 0xff) {
+ printf_P(PSTR(" JP39.2/3 jumpered (left)?"));
+ }
+ } else {
+ printf_P(PSTR(" OK"));
+ }
+ printf_P(PSTR(")"));
+}
+
+
int8_t PortExp::run (uint8_t subtest) {
+ #ifdef __AVR_ATmega328P__
+ if (hardwareVersion == 1) {
+ printf_P(PSTR("ERROR - nCS not controlable\n"));
+ return -1;
+ }
+ #endif
if (subtest == 0) {
while (wait(500) == EOF) {
printf_P(PSTR("\n => start ..."));
for (uint8_t i = 0; i < 8; i++) {
writeByte(0, ~(1 << i)); // IODIRA (Bank = 0)
- // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output
writeByte(0x12, (1 << i)); // GPIOA (Bank = 0)
printf_P(PSTR("\n Bank0 - GPA%d = 1"), i);
+ checkResponse (0x12, readByte(0x12), (1 << i));
wait(200);
writeByte(0x12, 0); // GPIOA (Bank = 0)
printf_P(PSTR("\n Bank0 - GPA%d = 0"), i);
+ checkResponse (0x12, readByte(0x12), 0);
writeByte(0, 0xff); // IODIRA (Bank = 0)
wait(200);
}
for (uint8_t i = 0; i < 8; i++) {
writeByte(1, ~(1 << i)); // IODIRB (Bank = 0)
- // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output
writeByte(0x13, (1 << i)); // GPIOB (Bank = 0)
printf_P(PSTR("\n Bank0 - GPB%d = 1"), i);
+ checkResponse (0x13, readByte(0x13), (1 << i));
wait(200);
writeByte(0x13, 0); // GPIOB (Bank = 0)
printf_P(PSTR("\n Bank0 - GPB%d = 0"), i);
+ checkResponse (0x13, readByte(0x13), 0);
writeByte(1, 0xff); // IODIRB (Bank = 0)
wait(200);
}