few things; mostly, I2C works now!; it was a hardware error

i had been leaving the RESET pin floating... this does not work.  it
must be externally biased - high, if you want the chip to work.. :) lol
partial-rewrite
Ben Blazak 2012-03-31 17:02:55 -07:00
parent f49d503698
commit b0b9335651
9 changed files with 294 additions and 213 deletions

View File

@ -13,7 +13,6 @@
// TODO
// int main(void) {
// return 0;
// }
void main(void) {
}

View File

@ -8,67 +8,26 @@
// TODO: this is not working yet
#if 0 // this is not the one we want; but it has all the right info
#include "lib-other/peter-fleury/i2cmaster/i2cmaster.h"
// so we can say `TWI_ADDRESS|I2C_WRITE`
#define TWI_ADDRESS (MCP23018_TWI_ADDRESS<<1)
uint8_t mcp23018_ready; // false
uint8_t mcp23018_init(void) {
// declare vars
uint8_t error;
// see if the device is ready
// - success: set `mcp23018_ready = true` and continue initializing
// - failure: return `error`; we can try again later
error = i2c_start(TWI_ADDRESS|I2C_WRITE);
if(error) {
return error;
} else {
mcp23018_ready = true;
i2c_stop(); // release bus
}
// set pin direction
// - unused : input : 1
// - rows : output : 0
// - columns : input : 1
i2c_start_wait(TWI_ADDRESS|I2C_WRITE);
i2c_write(IODIRA); // start register address
i2c_write(0b11000000); // IODIRA
i2c_write(0b11111111); // IODIRB
i2c_stop();
// set pull-up
// - unused : on : 1
// - rows : on : 1
// - columns : on : 1
i2c_start_wait(TWI_ADDRESS|I2C_WRITE);
i2c_write(GPPUA); // start register address
i2c_write(0b11111111); // GPPUA
i2c_write(0b11111111); // GPPUB
i2c_stop();
// set output pins high
// - rows : high : 1
// - other : low : 0 (or ignored)
i2c_start_wait(TWI_ADDRESS|I2C_WRITE);
i2c_write(OLATA); // start register address
i2c_write(0b00111111); // OLATA
i2c_stop();
return 0; // success
}
#endif
#include <util/delay.h>
#include <util/twi.h>
// #include "lib-other/arduino/arduino/libraries/Wire/utility/twi.h"
#include "lib-other/pjrc/blinky/print.h"
#include "lib-other/pjrc/blinky/usb_debug_only.h"
#define MCP23018_h_INCLUDE_PRIVATE
#include "mcp23018.h"
@ -86,27 +45,60 @@ uint8_t mcp23018_init(void) {
#define OLATA 0x14 // output latch register
#define OLATB 0x15
static void twi_init(void) {
// TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
TWSR |= (1<<TWPS1)|(1<<TWPS0); //dbg
// TWBR = ((F_CPU / 100000) - 16) / 2;
TWBR = 0xFF; //dbg
// TWCR = (1<<TWEA)|(1<<TWEN);
// ----------------------------------------------------------------------------
// dbg
// ----------------------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
#define blink_led(time1, time2) { \
/* Teensy 2.0 onboard LED on PD6
on high, off low */ \
PORTD |= (1<<6); \
_delay_ms(time1); \
PORTD &= ~(1<<6); \
_delay_ms(time2); \
}
static uint8_t twi_start(void) {
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
void blink_hex(uint8_t num) {
// initial blink (get ready)
blink_led(700, 200);
// 1st hex number
for (uint8_t i=0; i<(num/0x10); i++) {
blink_led(200, 100);
}
_delay_ms(400);
// 2nd hex number
for (uint8_t i=0; i<(num%0x10); i++) {
blink_led(200, 100);
}
}
// ---------------------------------------------------------------------------- // TWI
// ----------------------------------------------------------------------------
void twi_init(void) {
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
TWBR = ((F_CPU / 400000) - 16) / 2;
// TWSR |= (1<<TWPS1)|(1<<TWPS0); //dbg
// TWBR = 0xFF; //dbg
}
uint8_t twi_start(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_START)
return TWSR & 0xF8; // error
}
static void twi_stop(void) {
void twi_stop(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
while (!(TWCR & (1<<TWSTO)));
while (TWCR & (1<<TWSTO));
}
static uint8_t twi_send(uint8_t data) {
uint8_t twi_send(uint8_t data) {
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
@ -114,61 +106,22 @@ static uint8_t twi_send(uint8_t data) {
return TWSR & 0xF8; // error
}
static void hid_print_number_binary(uint8_t data) {
print("0b");
for(int8_t i=7; i>=0; i--) {
(data & (1<<i))
? pchar('1')
: pchar('0');
}
}
static void hid_print_number_hex(uint8_t data) {
print("0x"); phex(data);
}
static uint8_t try_address(uint8_t address) {
uint8_t error;
print("\naddress "); hid_print_number_binary(address);
twi_start();
error = twi_send(address);
twi_stop();
print(" error "); hid_print_number_hex(error);
return error;
}
// ----------------------------------------------------------------------------
// init function
// ----------------------------------------------------------------------------
uint8_t mcp23018_init(void) {
uint8_t error, address;
uint8_t ret;
twi_init();
// send address, wait
for (uint8_t i=0b000; i<=0b111; i++) {
address = (0b0100<<4)|(i<<1)|TW_WRITE;
error = try_address(address);
}
address = 0;
error = try_address(address);
// for (uint8_t i=0b0000000; i<=0b1111111; i++) {
// address = (i<<1)|TW_WRITE;
// error = try_address(address);
// if (! error == 0x20)
// return error;
// }
twi_start();
ret = twi_send( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE );
ret = twi_send(IODIRA);
ret = twi_send(0);
ret = twi_send(0);
ret = twi_send(0);
blink_hex(ret);
// uint8_t data[3];
//
// twi_init();
// twi_setAddress(MCP23018_TWI_ADDRESS);
//
// data[0] = IODIRA;
// data[1] = 0b00000000; // IODIRA
// error = twi_writeTo(MCP23018_TWI_ADDRESS, data, 2, true);
//
// data[0] = OLATA; // start register address
// data[1] = 0b00000000; // OLATA
// twi_writeTo(MCP23018_TWI_ADDRESS, data, 2, true);
return error;
}

View File

@ -37,12 +37,17 @@
o10 19o
power_positive Vdd(Vcc) +11 18o
I2C SCL +12 17o
I2C SDA +13 16o
I2C SDA +13 16+ RESET (see note)
o14-------15+ ADDR (see note)
* notes:
* ADDR (pin15): Set slave address to `0b0100000` by connecting to Vss(GND).
(The user-defined bits are the three least significant).
* RESET (pin16) must be externally biased. At least, this is true on the
MCP23017, so it seems like it should be true with the MCP23018. Since
we're not going to trigger it ourselves, we'll tie it high.
* <http://davidn.org/wp/?p=89>
* <http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293498979>
## Notes about Registers

View File

@ -1,5 +1,6 @@
# Documentation : Teensy 2.0
## Pinouts and Pin assignments
* `+` indicates pin
@ -45,6 +46,7 @@
internal pull-ups are enough (see datasheet section 20.5.1), but i think
for this project we'll want external ones.
## Notes about Registers
### General I/O (see datasheet section 10.2.1)
@ -101,6 +103,30 @@
* OCR = Output Compare Register
* TCCR = Timer/Counter Control Register
## I&sup2;C Status Codes (for Master modes)
### Master Transmitter
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x18` SLA+W has been transmitted; ACK has been received
* `0x20` SLA+W has been transmitted; NOT ACK has been received
* `0x28` Data byte has been transmitted; ACK has been received
* `0x30` Data byte has been transmitted; NOT ACK has been received
* `0x38` Arbitration lost in SLA+W or data bytes
### Master Receiver
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x38` Arbitration lost in SLA+R or NOT ACK bit
* `0x40` SLA+R has been transmitted; ACK has been received
* `0x48` SLA+R has been transmitted; NOT ACK has been received
* `0x50` Data byte has been received; ACK has been returned
* `0x58` Data byte has been received; NOT ACK has been returned
-------------------------------------------------------------------------------
Copyright &copy; 2012 Ben Blazak <benblazak.dev@gmail.com>

View File

@ -12,11 +12,7 @@ TARGET = ergodox-firmware
SRC = $(shell find -maxdepth 1 -name '*.c') \
$(shell find ./keyboard -name '*.c') \
$(shell find ./lib -name '*.c') \
./lib-other/peter-fleury/i2cmaster/twimaster.c \
./lib-other/pjrc/blinky/print.c \
./lib-other/pjrc/blinky/usb_debug_only.c \
./lib-other/arduino/arduino/libraries/Wire/utility/twi.c
$(shell find ./lib -name '*.c')
EXTRAINCDIRS = .

View File

@ -1,102 +0,0 @@
#include <stdio.h>
#include <util/delay.h>
#include "lib-other/pjrc/blinky/print.h"
#include "lib-other/pjrc/blinky/usb_debug_only.h"
#include "lib/data-types.h"
#define TEENSY_2_0_h_INCLUDE_PRIVATE
#include "keyboard/ergodox/teensy-2-0.h"
int blink_leds(void);
int test_i2c(void);
int test_kb_teensy(void);
int main(void);
// ----------------------------------------------------------------------------
int main(void) {
teensy_init();
KB_LED1_SET_PERCENT(.03);
KB_LED2_SET_PERCENT(.03);
KB_LED3_SET_PERCENT(.03);
// blink_leds();
// print("--------------");
test_i2c();
print("--------------");
test_kb_teensy();
}
// ----------------------------------------------------------------------------
int blink_leds(void) {
for (uint8_t i=0; i<3; i++) {
KB_LED1_SET(0x10);
KB_LED2_SET(0x20);
KB_LED3_SET(0xFF);
_delay_ms(500);
KB_LED1_SET(0x20);
KB_LED2_SET(0xFF);
KB_LED3_SET(0x10);
_delay_ms(500);
KB_LED1_SET(0xFF);
KB_LED2_SET(0x10);
KB_LED3_SET(0x20);
_delay_ms(500);
}
for (uint8_t i=0; i<2; i++) {
KB_LED1_OFF;
KB_LED2_OFF;
KB_LED3_OFF;
_delay_ms(500);
KB_LED1_ON;
KB_LED2_ON;
KB_LED3_ON;
_delay_ms(500);
}
bool counting_up = true;
for (uint8_t i=0;;) {
(counting_up) ? i++ : i--;
if (i == 0xFF)
counting_up = false;
else if (i == 0)
counting_up = true;
KB_LED1_SET(i/2);
KB_LED2_SET(i/2);
KB_LED3_SET(i/2);
_delay_ms(10);
}
}
int test_i2c(void) {
usb_init();
_delay_ms(500); // just to be safe
uint8_t ret;
uint8_t len;
char str[10];
print("\nhello");
ret = teensy_init();
print("\nteensy_init() returned: 0x"); phex(ret);
ret = mcp23018_init();
print("\nmcp23018_init() returned: 0x"); phex(ret);
usb_debug_flush_output();
return 0;
}
// ----------------------------------------------------------------------------
int test_kb_teensy(void) {
}

34
src/test/makefile Normal file
View File

@ -0,0 +1,34 @@
# -----------------------------------------------------------------------------
# This is mostly a stub at the moment, but I'm keeping it separate so I can
# mess with it later without changing the original
# -----------------------------------------------------------------------------
# Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
# Released under The MIT License (MIT) (see "license.md")
# Project located at <https://github.com/benblazak/ergodox-firmware>
# -----------------------------------------------------------------------------
TARGET = test
EXTRAINCDIRS = .
TEENSY_MAKE = $(MAKE) -f '../lib-other/pjrc/blinky/Makefile' \
TARGET='$(TARGET)' \
EXTRAINCDIRS='$(EXTRAINCDIRS)'
.PHONY: test_pwm test_twi
test_pwm:
$(TEENSY_MAKE) all \
SRC='test_pwm.c'
test_twi:
$(TEENSY_MAKE) all \
SRC='test_twi.c'
.PHONY: clean
clean:
$(TEENSY_MAKE) clean \
SRC='$(shell find -name '*.c')'

65
src/test/test_pwm.c Normal file
View File

@ -0,0 +1,65 @@
/* ----------------------------------------------------------------------------
* Test the Teensy 2.0 PWM code (see `#include`s)
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <util/delay.h>
#define TEENSY_2_0_h_INCLUDE_PRIVATE
#include "../keyboard/ergodox/teensy-2-0.h"
#include "../keyboard/ergodox/teensy-2-0.c"
#define bool uint8_t
#define true 1
#define false 0
void main(void) {
teensy_init();
for (uint8_t i=0; i<3; i++) {
KB_LED1_SET(0x10);
KB_LED2_SET(0x20);
KB_LED3_SET(0xFF);
_delay_ms(500);
KB_LED1_SET(0x20);
KB_LED2_SET(0xFF);
KB_LED3_SET(0x10);
_delay_ms(500);
KB_LED1_SET(0xFF);
KB_LED2_SET(0x10);
KB_LED3_SET(0x20);
_delay_ms(500);
}
for (uint8_t i=0; i<2; i++) {
KB_LED1_OFF;
KB_LED2_OFF;
KB_LED3_OFF;
_delay_ms(500);
KB_LED1_ON;
KB_LED2_ON;
KB_LED3_ON;
_delay_ms(500);
}
bool counting_up = true;
for (uint8_t i=0;;) {
(counting_up) ? i++ : i--;
if (i == 0xFF)
counting_up = false;
else if (i == 0)
counting_up = true;
KB_LED1_SET(i/2);
KB_LED2_SET(i/2);
KB_LED3_SET(i/2);
_delay_ms(10);
}
}

105
src/test/test_twi.c Normal file
View File

@ -0,0 +1,105 @@
/* ----------------------------------------------------------------------------
* Test for ACK on address write (with a Teensy 2.0 and I/O expander)
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <avr/io.h>
#include <util/twi.h>
#include <util/delay.h>
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
#define CPU_8MHz 0x01
#define CPU_4MHz 0x02
#define CPU_2MHz 0x03
#define CPU_1MHz 0x04
#define CPU_500kHz 0x05
#define CPU_250kHz 0x06
#define CPU_125kHz 0x07
#define CPU_62kHz 0x08
// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------
#define blink_led(time1, time2) { \
/* Teensy 2.0 onboard LED on PD6
on high, off low */ \
PORTD |= (1<<6); \
_delay_ms(time1); \
PORTD &= ~(1<<6); \
_delay_ms(time2); \
}
// ---------------------------------------------------------------------------- // TWI
// ----------------------------------------------------------------------------
void twi_init(void) {
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
TWBR = ((F_CPU / 100000) - 16) / 2;
// TWSR |= (1<<TWPS1)|(1<<TWPS0); //dbg
// TWBR = 0xFF; //dbg
}
uint8_t twi_start(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_START)
return TWSR & 0xF8; // error
}
void twi_stop(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
while (TWCR & (1<<TWSTO));
}
uint8_t twi_send(uint8_t data) {
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
return TWSR & 0xF8; // error
}
// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------
void main(void) {
CPU_PRESCALE(CPU_16MHz);
uint8_t ret;
twi_init();
for (uint8_t i=0;; i+=2) { // try all even (write) addresses
twi_start();
ret = twi_send(i); // i = address
twi_stop();
if (ret == 0x18) // SLA+W sent; ACK received
break;
if (i == 0xFE) // all done
break;
}
// blink the return value
// --- initial blink (get ready)
blink_led(700, 200);
// --- 1st hex number
for (uint8_t i=0; i<(ret/0x10); i++) {
blink_led(200, 100);
}
_delay_ms(400);
// --- 2nd hex number
for (uint8_t i=0; i<(ret%0x10); i++) {
blink_led(200, 100);
}
}