trying TWI on Nano Curiosity 4809

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm putting together a small protoboard project to read a MPU-6050 based gyro using I2C (fast mode). 

(I previously was able to do I/O using a Arduino Uno 3 w/ 328p.  And taking a break from my power converter project.)

 

Anyhow, I'm want to know if the internal pull-up can work for this, and if not, how to size the pullup.

 

The Curiosity Nano board runs the processor at 3.3v.   The MPU-6050 is advertised to run at 3.3v and runs w/ fast mode (oh, or standard mode) I2C.

 

The Nano pull-up resistor (according to the 48-pin datasheet) is ~ 35 kOhm (low 20 kOhm, high 50 kOhm).

The Nano TWI pin capacitance is rated at 20 nF.

The I2C spec indicates that t_rise for fast mode (400 kHz) shall be 20-300 ns, for normal mode (100 kHz) t_rise shall be less than 1000 ns.

Also from the I2C spec, I find Rp min is 0.5 kOhm, and Rp max = t_rise / (0.8473*Cb)

where Rp max is in kOhm, t_rise is in ns and Cb, the total bus capacitance, is in pF.

At best, t_rise = 300 ns and Cb = 20 nF giving 17 kOhm.  This is looking bad to me.  I'd rather take 100 ns, 100 nF, giving 1.1 kOhm (pulling ~ 3 mA).

 

Or, for standard mode, t_rise < 1000 ns.  If I assume Cb is 100 pF, then I get 11.8 kOhm,

 

Q1: Is the 100 pF bound on bus capacitance for breadboard w/ 2 in wires valid?

Q2: Is the conclusion that I should use 1 kOhm external pullup valid?

 

My next step is the software.   The AVR 0-series TWI is a bit more complex than the 328p. 

The first step I've done is to make a finitie state machine diagram.  (I can post if you care.)

And I've started writing code based on my state machine diagram.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Look at your maths.    See what nF or pF mean.

 

Typical chip capacitance is 5pF.   A breadboard or close tracks on a pcb might add 20pF.    I2C spec says < 400pF for total bus capacitance.

Your single Slave device means that bus capacitance is fine i.e. 25pF < 400pF

 

There is no way that you can use internal AVR pullups.

Typical external pullups might be 2k2 for 3.3V or 4k7 for 5V.

The Curiosity can adjust the voltage to 3.3V or 5V e.g. use 3.3V for 3.3V I2C chips.

 

100kHz is standard I2C bus speed.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would hope it was less than 100pf, but it may be more than 10 or 20pf, I use a 1.8kOhm pull-up on things that have 3V3, but the current draw is irritating.

 

You might look at the Arduino twi for that chip if you want to cheat (that is my plan).

 

https://github.com/arduino/Ardui...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

Look at your maths.    See what nF or pF mean.

 

 

Right these should all be pF; thanks for the catch.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1 kOhm for now.    Here is the setup.

 

 

Here is my state machine (FSM) diagram.  It covers three function calls: init, write and read.  init() will set up the I2C and enable.  write() will write n bytes; it is covered by the top portion of the state diagram.  read() will read n bytes; it is covered by the bottom portion.   The READY state represents no activity.  ADDR SEND is a wait state while the bus is transferring an address/rw byte.  DATA SEND and RECV are wait states while the bus is active sending or receiving data, respectively.   Transitions use notation of the form "event[condition]/action".

intr[WIF] means "interrupt occurred with WIF bit set in MSTATUS"

ACK/NACK represent values of the RXACK bit in MSTATUS

The condition ERR represents BUSERR or ARBLOST. 

The action "stop" means emit a STOP (MCMD in MCTRLB).

The action "attr" means write to MADDR.

The action "read" means write (top portion) or read (bottom portion) via MDATA.

 

Does this look reasonable?

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The m4809 has two Interrupts.

 

ISR(TWI0_TWIM_vect){
	TWI_MasterInterruptHandler();
}

ISR(TWI0_TWIS_vect){
	TWI_SlaveInterruptHandler();
}

 

And to my eyes, the Arduino m4809 code looks to have two state machines driven by an ISR, one for the master and the other for the slave.

 

The old 328p has one interrupt that drives a single state machine that does both master and slave.

 

https://github.com/arduino/Ardui...

 

I wonder if the master ISR can talk to the slave ISR on the same m4809?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ron_sutherland wrote:

The m4809 has two Interrupts.

 

ISR(TWI0_TWIM_vect){
	TWI_MasterInterruptHandler();
}

ISR(TWI0_TWIS_vect){
	TWI_SlaveInterruptHandler();
}

 

And to my eyes, the Arduino m4809 code looks to have two state machines driven by an ISR, one for the master and the other for the slave.

 

The old 328p has one interrupt that drives a single state machine that does both master and slave.

 

https://github.com/arduino/Ardui...

 

I wonder if the master ISR can talk to the slave ISR on the same m4809?

 

 I'm only handling the master to start.  In fact, it looks to me like there can be independent master and slave as well as combined master-slave.  Work to go.

 

EDIT: According to the 48-pin 4809 datasheet,  pins 46/47, as well as pins 12/13, can operate in combined mode, whereas pins 36/37 support slave-only.

EDIT: And to anwer master-ISR/slave-ISR interaction question, I think a combined state-machine is way to approach.

Last Edited: Sun. Jan 19, 2020 - 11:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is an updated TWI Master state diagram.  

 

My code was not working at all, then realized I forgot to initialize the MSTATUS BUSSTATE to IDLE.    Now getting the address out but realized my device may want repeated start. 

 

The following update provides repeated START (via rtw = read-then-write, and wtr = write-then-read).  I will be working on adding SLAVE functionality in the future.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Matt -

 

Do you have a reference for that style of state machine diagram?

 

Thanks

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ron_sutherland wrote:

And to my eyes, the Arduino m4809 code looks to have two state machines driven by an ISR, one for the master and the other for the slave.

If I correctly skimmed the following, two ISR both in the slave (master polls)

Getting started ATtiny 1 & 0 series / Application Notes | AVR Freaks

...

- Getting started with TWI -> See the attachment

...

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

Matt -

 

Do you have a reference for that style of state machine diagram?

 

Thanks

Jim

 

This qualifies as a UML State Machine.  (Also qualifies as Harel StateChart, I believe.)

The only difference from FSMs here is the notation for transitions, and the decision psedo-states (the diamonds).

 

Matt

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have never seen the double-line. Nor the decision diamonds without a "y" or "N" at two points.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

ka7ehk wrote:

Have never seen the double-line. Nor the decision diamonds without a "y" or "N" at two points.

 

Jim

 

The double line is poetic license, instead of two distinct lines.

The use if [condition] vs Y N is part of the State Machine syntax, as is the keyword else (though else does belong in brackets -- will fix).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
that style of state machine diagram?

How do you mean? Looks like a pretty standard style to me....

 

https://en.wikipedia.org/wiki/State_diagram

 

EDIT

 

Hmmm - that Wikipedia seems more focussed on the hardware/logic state diagrams.

 

Perhaps this is better:

 

http://www.cs.unc.edu/~stotts/145/CRC/state.html

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Jan 27, 2020 - 02:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jim,

 

I think this is a legal form using fork-join pseudo-states to replace my double lines..

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's the status.   I have coded up something that is mostly consistent with the state machine.  

I'm trying to read gyro data from the M6050 IMU over I2C with Curiosity Nano w/ mega4809.  I did have this working on mega328p w/ different code.

I can do writes but not write-read cycles (w/ repeated start):  After the address is sent I apparently get a NACK.

 (I did have code working for mega328p on this same IMU.)  I don't have access to my scope right now so have not yet tried looking at the bus.

I'm logging errors and end states.  I'm performing several two-data-byte writes to set up registers, followed by a one data-byte write and one data-byte read.  Here is the log:

 

hello
TWM_E_NONE => TWM_M_READY
TWM_E_NONE => TWM_M_WAIT_ADDR_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND
TWM_E_NONE => TWM_M_READY
TWM_E_NONE => TWM_M_WAIT_ADDR_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND
TWM_E_NONE => TWM_M_READY
TWM_E_NONE => TWM_M_WAIT_ADDR_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND
TWM_E_NONE => TWM_M_WAIT_DATA_SEND                                              
TWM_E_NONE => TWM_M_READY                                                       
TWM_E_NONE => TWM_M_WAIT_ADDR_SEND                                              
TWM_E_NONE => TWM_M_WAIT_DATA_SEND                                              
TWM_E_NONE => TWM_M_WAIT_DATA_SEND                                              
TWM_E_NONE => TWM_M_READY                                                       
-                                                                               
TWM_E_NONE => TWM_M_WAIT_ADDR_SEND                                              
TWM_E_GOT_NACK => TWM_M_READY                                                   
                                                                                
 00 00 00 00 00 00 

 

And here is the code.  (You folks always say you want to see everything.   This is almost everything.

 

#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU 20000000UL

#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "twm.h"

#ifndef STATIC
#define STATIC /* */
#endif

#include "../nano_bw.c"
#include "../avr0_dump.c"

STATIC void dump_data6(USART_t *usart, uint16_t addr) {
  uint8_t *p = (uint8_t*)addr;
  char buf[4];

  for (uint8_t i = 0; i < 6; i++) {
    cnvt_u8(p[i], buf);
    usart_putchar(usart, ' ');
    usart_putchar(usart, buf[0]);
    usart_putchar(usart, buf[1]);
  }
  usart_putchar(usart, '\r');
  usart_putchar(usart, '\n');
}


#if USE_TASKING
#define TWI_USE_TASKING 1
#endif
#if TWI_USE_TASKING
#define twi_idle_task(TID) octos_idle_task(TID)
#define twi_wake_task(TID) octos_wake_task(TID)
#else
#define twi_idle_task(TID) /* */
#define twi_wake_task(TID) /* */
#endif


/* === TWI logging === */

char *twm_modestr(twi_master_mode_t mode) {
  switch (mode) {
  case TWM_M_UNKNOWN: return "TWM_M_UNKNOWN"; break;
  case TWM_M_READY: return "TWM_M_READY"; break;
  case TWM_M_WAIT_ADDR_SEND: return "TWM_M_WAIT_ADDR_SEND"; break;
  case TWM_M_WAIT_DATA_RECV: return "TWM_M_WAIT_DATA_RECV"; break;
  case TWM_M_WAIT_DATA_SEND: return "TWM_M_WAIT_DATA_SEND"; break;
  default: return "TWM_M_OTHER"; break;
  }
  return "";
}

char *twm_errstr(twi_master_error_t err) {
  switch (err) {
  case TWM_E_UNKNOWN: return "TWM_E_UNKNOWN"; break;
  case TWM_E_NONE: return "TWM_E_NONE"; break;
  case TWM_E_NOT_READY: return "TWM_E_NOT_READY"; break;
  case TWM_E_BUS_ERROR: return "TWM_E_E_BUS_ERROR"; break;
  case TWM_E_ARB_LOST: return "TWM_E_ARB_LOST"; break;
  case TWM_E_GOT_NACK: return "TWM_E_GOT_NACK"; break;
  default: return "TWM_E_OTHER"; break;
  }
  return "";
}

struct {
  twi_master_error_t e;
  twi_master_mode_t m;
} twm_log_q[100];

uint8_t nq = 0;

void log_add(twi_master_error_t e, twi_master_mode_t m) {
  twm_log_q[nq].e = e;
  twm_log_q[nq].m = m;
  nq += 1;
}

void log_report(USART_t *usart) {
  uint8_t i;

  for (i = 0; i < nq; i++) {
    if ((twm_log_q[i].e == 0) && (twm_log_q[i].m == 0)) {
      usart_putline(usart, "-");
    } else {
      usart_putstring(usart, twm_errstr(twm_log_q[i].e));
      usart_putstring(usart, " => ");
      usart_putline(usart, twm_modestr(twm_log_q[i].m));
    }
  }
  usart_putline(usart, "");
  nq = 0;
}

/* === TWI master library === */

STATIC void
twi_master_init(twm_t *twm, TWI_t *twi, uint8_t baud)
{
  twm->io = twi;
  twm->io->MBAUD = baud;
  twm->io->MSTATUS = TWI_BUSSTATE_IDLE_gc;
# if TWI_USE_TASKING
  twm->io->MCTRLA = 0xC0;		/* intr on read/write */
# else
  twm->io->MCTRLA = 0x00;		/* no interrupts */
# endif
  twm->mode = TWM_M_UNKNOWN;
  twm->tid = 0;
}

STATIC void
twi_master_on(twm_t *twm)
{
  twm->io->MCTRLA |= 0x01;		/* enable master */
  twm->io->MCTRLB = 0x40;		/* flush */
  twm->mode = TWM_M_READY;
}

STATIC void
twi_master_off(twm_t *twm)
{
  twm->io->MCTRLA &= 0x01;
}

STATIC void
twi_master_reset(twm_t *twm)
{
  twm->io->MCTRLB = 0x40;		/* flush */
  twm->io->MCTRLA |= 0x01;		/* enable master */
  twm->mode = TWM_M_READY;
}

STATIC void
twi_master_stop(twm_t *twm)
{
  twm->io->MCTRLB = TWI_MCMD_STOP_gc;
  twm->mode = TWM_M_READY;
}

USART_t *usart;

STATIC twi_master_error_t
twm_send_addr(twm_t *twm, uint8_t addr)
{
  twi_master_error_t err;
  uint8_t status;

  if (twm->mode != TWM_M_READY) {
    return TWM_E_NOT_READY;
  }

  /* send address (copied to TWIn.DATA on xmit) */  
  twm->io->MADDR = addr;
  twm->mode = TWM_M_WAIT_ADDR_SEND;
  log_add(TWM_E_NONE, TWM_M_WAIT_ADDR_SEND);

  twi_idle_task(twm->tid);		/* wait for intr, if used */
  while (twm->io->MSTATUS &= 0x40);	/* spin on WIF */
  status = twm->io->MSTATUS;		/* WIF clr nxt op <= check  */

  if (status & TWI_BUSERR_bm) {
    twi_master_reset(twm);
    log_add(TWM_E_BUS_ERROR, TWM_M_READY);
    return TWM_E_BUS_ERROR;
  }
  if (status & TWI_ARBLOST_bm) {
    twi_master_reset(twm);
    log_add(TWM_E_ARB_LOST, TWM_M_READY);
    return TWM_E_ARB_LOST;
  }
  
  if (status & TWI_RXACK_bm) {
    twi_master_stop(twm);
    log_add(TWM_E_GOT_NACK, TWM_M_READY);
    return TWM_E_GOT_NACK;
  }

  return TWM_E_NONE;
}


STATIC twi_master_error_t
twm_send_data(twm_t *twm, uint8_t data)
{
  uint8_t status;
  
  twm->io->MDATA = data;
  twm->mode = TWM_M_WAIT_DATA_SEND;
  log_add(TWM_E_NONE, TWM_M_WAIT_DATA_SEND);

  twi_idle_task(twm->tid);		/* wait for intr, if used */
  while (twm->io->MSTATUS &= 0x40);	/* spin on WIF */
  status = twm->io->MSTATUS;

  if (status & TWI_BUSERR_bm) {
    twi_master_reset(twm);
    log_add(TWM_E_BUS_ERROR, TWM_M_READY);
    return TWM_E_BUS_ERROR;
  }
  if (status & TWI_ARBLOST_bm) {
    twi_master_reset(twm);
    log_add(TWM_E_ARB_LOST, TWM_M_READY);
    return TWM_E_ARB_LOST;
  }
  
  if (status & TWI_RXACK_bm) {
    twi_master_stop(twm);
    log_add(TWM_E_GOT_NACK, TWM_M_READY);
    return TWM_E_GOT_NACK;
  }

  return TWM_E_NONE;
}

STATIC twi_master_error_t
twm_recv_data(twm_t *twm, uint8_t *data)
{
  uint8_t status;
  
  twm->mode = TWM_M_WAIT_DATA_RECV;
  log_add(TWM_E_NONE, TWM_M_WAIT_DATA_RECV);

  twi_idle_task(twm->tid);		/* wait for intr, if used */
  while (twm->io->MSTATUS &= 0x80);	/* spin on RIF */
  status = twm->io->MSTATUS;

  if (status & TWI_BUSERR_bm) {
    twi_master_reset(twm);
    return TWM_E_BUS_ERROR;
  }
  if (status & TWI_ARBLOST_bm) {
    twi_master_reset(twm);
    log_add(TWM_E_ARB_LOST, TWM_M_READY);
    return TWM_E_ARB_LOST;
  }
  
  if (status & TWI_RXACK_bm) {
    twi_master_stop(twm);
    log_add(TWM_E_GOT_NACK, TWM_M_READY);
    return TWM_E_GOT_NACK;
  }

  *data = twm->io->MDATA;
  twm->mode = TWM_M_READY;
  log_add(TWM_E_NONE, TWM_M_READY);
  return TWM_E_NONE;
}

STATIC twi_master_error_t
twi_master_write(twm_t *twm, uint8_t addr, uint8_t n, uint8_t *data)
{
  twi_master_error_t err;
  uint8_t status;

  err = twm_send_addr(twm, (addr << 1)|0x00);
  if (err != TWM_E_NONE) return err;
  
  while (n-- > 0) {
    err = twm_send_data(twm, *data++);
    if (err != TWM_E_NONE) return err;
  }

  twi_master_stop(twm);
  log_add(TWM_E_NONE, TWM_M_READY);
  return TWM_E_NONE;
}

STATIC twi_master_error_t
twi_master_read(twm_t *twm, uint8_t addr, uint8_t n, uint8_t *data)
{
  twi_master_error_t err;
  uint8_t status;

  err = twm_send_addr(twm, (addr << 1)|0x01);
  usart_putline(usart, twm_errstr(err));
  if (err != TWM_E_NONE) return err;
  
  while (n-- > 0) {
    err = twm_recv_data(twm, data++);
    if (err != TWM_E_NONE) return err;
  }

  twi_master_stop(twm);
  log_add(TWM_E_NONE, TWM_M_READY);
  return TWM_E_NONE;
}


STATIC twi_master_error_t
twi_master_write_read(twm_t *twm, uint8_t addr,
		      uint8_t nw, uint8_t *wdata,
		      uint8_t nr, uint8_t *rdata)
{
  twi_master_error_t err;
  uint8_t status;

  err = twm_send_addr(twm, (addr << 1)|0x00);
  if (err != TWM_E_NONE) return err;
  
  while (nw-- > 0) {
    err = twm_send_data(twm, *wdata++);
    if (err != TWM_E_NONE) return err;
  }

  twm->io->MCTRLB = TWI_MCMD_REPSTART_gc; /* repeated START */
  
  err = twm_send_addr(twm, (addr << 1)|0x01);
  if (err != TWM_E_NONE) return err;
  
  while (nr-- > 0) {
    err = twm_recv_data(twm, rdata++);
    if (err != TWM_E_NONE) return err;
  }

  twi_master_stop(twm);
  twm->mode = TWM_M_READY;
  log_add(TWM_E_NONE, TWM_M_READY);
  return TWM_E_NONE;
}


/* === application code === */

STATIC void usart_on(USART_t *usart) {
  PORTB.PIN0CTRL = PORT_PULLUPEN_bm;	/* enable TX pullup on PB0 */
  PORTB.OUTSET = PIN0_bm;		/* needed? */
  PORTB.DIRSET = PIN0_bm;
  usart->CTRLB = USART_TXEN_bm;		/* enable TX */
}

STATIC void usart_off(USART_t *usart) {
  usart->CTRLB &= ~USART_TXEN_bm;
  PORTB.PIN0CTRL &= PORT_PULLUPEN_bm;
}

twm_t twm0;				/* TWI master object */

#if TWI_USE_TASKING
ISR(TWI0_TWIM_vect) {
  twi_wake_task(twm0.tid);
}
#endif

twi_master_error_t imu_write_reg(uint8_t addr, uint8_t reg, uint8_t val) {
  uint8_t data[2];

  data[0] = reg; data[1] = val;
  return twi_master_write(&twm0, addr, 2, data);
}

twi_master_error_t imu_read_reg(uint8_t addr, uint8_t reg, uint8_t *val) {
  return twi_master_write_read(&twm0, addr, 1, &reg, 1, val);
}


int main(void) {
  uint8_t addr;
  uint8_t imu[6];
  twm_t *twm = &twm0;
  twi_master_error_t err;
  uint8_t doit = 1;

# if USE_TASKING
  octos_init(OCT_TASK_6);
# endif
  
  /* Wait for user button-click. */
  nano_button_wait();

  /* Set up watchdog timer */
  CCP = CCP_IOREG_gc;
  WDT.CTRLA = WDT_PERIOD_8KCLK_gc;

  // Setup 20MHz clock.
  CCP = CCP_IOREG_gc;
  CLKCTRL.MCLKCTRLB = 0;

  // Setup comm.
  usart = &USART3;
  usart_init(usart, BAUD_FROM_RATE(BAUDRATE));
  usart_on(usart);
  _delay_ms(1);
  usart_putline(usart, "hello");

  // Setup Button pullup (though not needed).
  PORTF.PIN6CTRL = PORT_PULLUPEN_bm;

  // Setup LED.
  PORTF.DIRSET = PIN5_bm;

  // Setup scope trigger.
  PORTB.DIRSET = PIN4_bm;
  PORTB.OUTCLR = PIN4_bm;
  
  // Setup TWI pins.
  //   Section 15.2 in 0-series datasheet says:  The PORT pin configuration
  //   also controls input and output selection of other device functions.
  PORTA.DIRSET = PIN2_bm | PIN3_bm;

  // TWI master setup
  twi_master_init(twm, &TWI0, 85);
# if USE_TASKING
  twm->tid = octos_cur_task();
# endif
  twi_master_on(twm);
  log_add(TWM_E_NONE, TWM_M_READY);

  addr = 0x6B;				/* IMU address */

  imu_write_reg(addr, 0x6B, 0x00);  /* device control: wake it up */
  imu_write_reg(addr, 0x19, 80);    /* sample rate => 100 Hz */
  imu_write_reg(addr, 0x1A, 0x03);  /* FSYNC=0, 42Hz gyro, 44Hz acc */
  imu_write_reg(addr, 0x1B, 0x08);  /* 27: gyro config */
  _delay_ms(1);

  log_add(TWM_E_UNKNOWN, TWM_M_UNKNOWN);

  //PORTB.OUTSET = PIN4_bm;	      /* scope trigger */

  memset(imu, 0, 6);
  while (doit) {
    err = imu_read_reg(addr, 0x43, &imu[0]);
    //err = imu_read_reg(addr, 0x44, &imu[1]);
    //err = imu_read_reg(addr, 0x45, &imu[2]);
    //err = imu_read_reg(addr, 0x46, &imu[3]);
    //err = imu_read_reg(addr, 0x47, &imu[4]);
    //err = imu_read_reg(addr, 0x48, &imu[5]);

    wdt_reset();
    log_report(usart);
    dump_data6(usart, (uint16_t)imu);
    _delay_ms(500);
    doit = 0;
  }

  while (1);				/* restart via watchdog */
}
/* twm.h */

#ifndef twm_h__
#define twm_h__

typedef enum {
  TWM_M_UNKNOWN = 0,
  TWM_M_READY,
  TWM_M_WAIT_ADDR_SEND,
  TWM_M_WAIT_DATA_RECV,
  TWM_M_WAIT_DATA_SEND,
} twi_master_mode_t;

typedef enum {
  TWM_E_UNKNOWN = 0,
  TWM_E_NONE,
  TWM_E_NOT_READY,
  TWM_E_BUS_ERROR,
  TWM_E_ARB_LOST,
  TWM_E_GOT_NACK,
  TWM_E_OTHER = 255,
} twi_master_error_t;

typedef struct {
  TWI_t *io;
  twi_master_mode_t mode;
  uint8_t tid;				/* task id */
} twm_t;

#endif
/* --- last line --- */

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Trying to debug my code.  The above has errors.  I even ordered a logic analyzer to keep hacking.

 

In the mean time, here's an updated state diagram.  I separated out ERR (=BUS ERROR | ARB LOST) and NACK tests because the data sheet explicitly states that BUSERR ARBLOST should be checked first.