eriksl / usitwislave

Software TWI/I2C implementation for ATtiny devices using USI.
Other
45 stars 14 forks source link

Arduino Wrapper - Need a little more clarity on usage #2

Open gismofx opened 10 years ago

gismofx commented 10 years ago

Hey Erik,

I'm in the process of writing a wrapper for your updated library for Arduino and with the ATtiny Tiny Cores. Anyway, I've got something primitive actually working with your library, but I'm looking for more clarification on implementation so I can better experiment and document the wrapper code I'm making. From what I've incovered, your code seems much simpler in terms of implementation which I like.

Regarding clarification: For instance: calling usi_twi_slave(I2C address, use_sleep,data_callback, idle_callback); this Initializes the TWI. That seems like that's the only thing needed to get this code running.

Usage of data_callback((uint8_t input_buffer_length, const uint8_t input_buffer, uint8_t output_buffer_length, uint8_t *output_buffer);)

Things I want to clarify:

  1. The *data_callback function that I create should test the buffers to determine if it's a read or write transaction and then set the inputs accordingly. correct? Are the length parameters 0 initialized or 1 initialized? For example, in my demo, I want to send two bytes, so when my master reads the device, I need to set the output buffer length = 2 and then create dataOut[2] = {b1,b2}; output_buffer=dataOut;
  2. *idle_callback - Only called when SLEEP is disabled? Idle callback is called after every stop condition. What's it's purpose? Or how is it useful?
  3. use_sleep seems like a boolean, but you use uint8_t? Any reason? Consistency 0 or 1 (false/true) What happens when sleep is enabled and when it's disabled? Other effects of the I2C. I have only used 0 in my testing.

Just in case, If you're not familiar with arduino..There are two main blocks that are needed so it compiles correctly.

void setup(){}//This is where you initialize things. Only runs once

and

void loop(){} //This code loops

--So Implementing your code in arduino would look something like this:--

void setup() { usi_twi_slave(a,b,callback,idle); }

void loop() { //do nothing or do something }

static void twi_callback(byte input_buffer_length, const byte input_buffer, byte output_buffer_length, byte *output_buffer) { //do stuff here prepare data to send out or process incoming data. }

void idle_callback() { //idle task? }

Thanks for all your help and I'm happy to further clarify my questions if needed.

eriksl commented 10 years ago

I'm in the process of writing a wrapper for your updated library for Arduino and with the ATtiny Tiny Cores.

Cool!

this Initializes the TWI. That seems like that's the only thing needed to get this code running.

Yep!

Usage of data_callback((uint8_t input_buffer_length, const uint8_t input_buffer, uint8_t output_buffer_length, uint8_t *output_buffer);)

Things I want to clarify:

  1. The *data_callback function that I create should test the buffers to determine if it's a read or write transaction and then set the inputs accordingly. correct?

No.

The data callback is called when there is data available to the application.

The first function does not only initialize twi, it also takes over control, until data is received, which is handed to the application via the data callback.

Are the length parameters 0 initialized or 1 initialized?

It's C, so arrays and lengths are always zero-based.

*idle_callback - Only called when SLEEP is disabled? Idle callback
is called after every stop condition. What's it's purpose? Or how is
it useful?

That's incorrect. The idle_callback is called frequently when sleep is disabled and it's called less frequently when sleep is enabled. Please keep in mind the cpu goes out of sleep for various reasons, e.g. any interrupts, including the START condition interrupt.

use_sleep seems like a boolean, but you use uint8_t? Any reason?
Consistency 0 or 1 (false/true)

Yes it's a bool, but there is no sense in using a bool, because an uint8_t is the smallest unit that can be passed. If you use a bool, there is a risk it's expanded to be an "int" and and "int" is 16 bits on AVR. Better use uint*_t types.

What happens when sleep is enabled and when it's disabled? Other effects of the I2C.
I have only used 0 in my testing.

When sleep is on, the cpu uses much less energy, but it may miss a STOP condition from another device, because USI doesn't have a STOP condition interrupt. OTOH I've been running them in "sleep" mode for two years now, no problem in practise. If you see strange things, first thing to try is to disable sleep mode.

Just in case, If you're not familiar with arduino..There are two main blocks that are needed so it compiles correctly.

I am not familiar with Arduino indeed, and I am not planning to change that ;-)

gismofx commented 10 years ago

Thanks for writing me back! You've answered a lot! For now, what I have working is buggy at best.

I still really don't understand the *idle_callback usage. When would I use it? How is it used? Any simple example?

Again, touching back on data_callback: When some transaction is initiated with this device, data_callback is executed. -if data is received(master sends data) then: input_buffer_length = number of bytes received const input_buffer, = data byte(s) (is an array of bytes (then the code can do something with this information)

-if data is being requested(master requests data/ master reads), the program must then define the following in the code: output_buffer_length, (Size of output buffer array- must be greater than or equal to 1 ( >= 1) output_buffer = array of bytes to be sent back to master <- if true, I am getting some errors setting this to an array in my callback.

Maybe you have a simple example of data_callback as well? something the sends and receives 2 bytes.

This is funny behavior, but currently I can detect the detect the device on the bus, but it hangs when I attempt to read data 1 byte of data.If I unplug the ATTiny and plug it back it back in during a read request, it will return the byte. The returned byte is either 0 or the correct value.

btw, I'm studying usitwislave.c around line 242 //process read request from master

Thanks!

eriksl commented 10 years ago

I still really don't understand the *idle_callback usage. When would I use it? How is it used? Any simple example?

I am using to reset the watchdog and also make led blink, so you can see it's alive. Nothing really more useful I think.

Currently I can detect the detect the device on the bus, but it hangs when I attempt to read data 1 byte of data. Sometimes if I unplug the ATTiny and plug it back it back in during a read request, it will return a byte.

You might want to have a look here: http://github.com/eriksl/attiny861_1

Also have all conditions been met to be able to communicate i2c at all:

gismofx commented 10 years ago

regarding hardware setup: Using external pull-ups and that are correctly sized and I'm running at 8mhz internal, but calibrated.

I'm reading through your code main.c here:

static void process_input(uint8_t if_input_buffer_length, const uint8_t if_input_buffer, uint8_t if_output_buffer_length, uint8_t *if_output_buffer)

If I have any questions, I'll post back. Thanks!

eriksl commented 10 years ago

regarding hardware setup: Using external pull-ups and that are correctly sized and I'm running at 8mhz internal, but calibrated.

Okay. The clock doesn't need to be calibrated though, it's not even required to be very precise. That's the beauty of i2c (and spi) as well, it's completely asynchronous, using the separate clock line.

I'm reading through your code here:

static void process_input(uint8_t if_input_buffer_length, const uint8_t if_input_buffer, uint8_t if_output_buffer_length, uint8_t *if_output_buffer)

And what is exactly your question?

gismofx commented 10 years ago

Thanks for the quick reply. I'm actually reading your code now. When I'm finished reading, I'll post my questions(s).

Thanks!