Closed dragoncoder047 closed 1 year ago
The way that Arduino Wire is implemented is very peculiar; it buffers up all the calls to Wire.write()
, and then sends them all when you call Wire.endTransmission()
. I've written my own library which I believe does things the way I2C was intended to work:
Tiny I2C Routines for all AVR Microcontrollers
However, it only does I2C Master.
In uLisp I have used my routines for AVR microcontrollers, as you mentioned, and the Arduino routines for all the others.
The only time I've implemented an I2C Slave device is here:
and that was using the ATtiny1614 which is a processor that has an I2C Slave peripheral. It was hard work figuring out how to get it to work; you might find that article useful. I don't think I'd trust an ATtiny85 to be able to do it properly.
IMHO, I think that the Arduino Wire
library is at fault here, not TinyWireS
. I did get bytes to be read, and was able to write bytes, they just ended up in unpredictable positions depending on how many bytes I wrote at once. If you want to have a go at sidestepping the Arduino library on an ESP32 (and going straight to the ESP-IDF level functions) I think this page would be helpful: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html
Thanks, but I don't think I'm going to start rewriting the ESP32 I2C code. If it works don't fix it!
Well, I was able to try out the I2C routines on an ATmega328P (Arduino Uno) and they have the same lack of success as the ESP32.
The ATtiny85 ACK's at the usual addresses using the port scanner, as usual. But upon reading things, it's even weirder:
uLisp 4.4b
319> (with-i2c (str 5) (write-byte 0 str) (restart-i2c str) (dotimes (_ 4) (print (read-byte str))))
10
10
10
10
nil
319> ;; Expected output would have been "55 220 128 0 nil" here,
319> ;; as that is what I initially had the ATtiny85's registers set to.
319> (with-i2c (str 5) (write-byte 0 str) (dolist (x '(#xDE #xAD #xBE #xEF)) (write-byte x str)))
nil
319> (with-i2c (str 5) (write-byte 0 str) (restart-i2c str) (dotimes (_ 4) (print (read-byte str))))
10
10
10
10
nil
319>
I suspect one of two things now: either a) the ATtiny85 is not responding correctly, or b) it is, but both the Uno and the ESP32 don't take too kindly to clock-stretching. (I'm not a hardware expert; please correct me if you know for certain they do implement clock-stretching properly.) I'll have a go at setting the ESP32's SCL frequency to something super low like 10KHz and see if that makes any difference.
To test the Wire library I made a simple I2C REPL and put it in this gist.
Input: a5[w0]r4
produces this output (the ATtiny85 is listening at address 0x05):
Target address 0x5
Begin transmission at target address 0x5
Writing byte 0
End transmission ACK
Requesting 4 bytes from address 0x5:
0 255 255 255
a5[w0]r1r1r1r1
has a little better luck:
Target address 0x5
Begin transmission at target address 0x5
Writing byte 0
End transmission ACK
Requesting 1 bytes from address 0x5:
0
Requesting 1 bytes from address 0x5:
220
Requesting 1 bytes from address 0x5:
128
Requesting 1 bytes from address 0x5:
0
Just to see if the REPL program is acting OK, I tested this with the MAX17048 which comes on the dev board.
Input: a54[w8]r2
Output:
Target address 0x36
Begin transmission at target address 0x36
Writing byte 0x8
End transmission ACK
Requesting 2 bytes from address 0x36:
0 18
Seems to be working. I guess the ATtiny85's clock-stretching is confusing the ESP32.
Off-topic but I don't know where else to get ahold of Mr. AVR Expert:
I'm trying to modify the ATtiny85 program to flash an LED when it receives stuff, but now avrdude is giving me this error:
Using Port : usb
Using Programmer : usbtiny
avrdude: usbdev_open(): Found USBtinyISP, bus:device: 001:054
avrdude: Warning: cannot open USB device: Permission denied
avrdude: usbdev_open(): Found USBtinyISP, bus:device: 001:060
avrdude: Warning: cannot open USB device: Permission denied
avrdude: Error: Could not find USBtiny device (0x1781/0xc9f)
I'm just using a sparkfun usb ATtiny85 programmer and the default settings. I was previously able to upload programs, but now something has changed. Any idea what is going on?
What core are you using?
With the SparkFun programmer you don't select a USB port from the Port menu - I sometimes forget that and wonder why the USB port isn't showing up.
Also, sometimes things connected to the ATtiny85 circuit can interfere with the upload; try disconnecting something while you upload.
I'm using David A. Mellis's core, and the ATtiny85 is plugged directly into the socket in the programmer. I remove it from the breadboard.
For the heck of it I hit "upload" with the programmer unplugged, and I got this:
Using Port : usb
Using Programmer : usbtiny
avrdude: usbdev_open(): Found USBtinyISP, bus:device: 001:054
avrdude: Warning: cannot open USB device: Permission denied
avrdude: Error: Could not find USBtiny device (0x1781/0xc9f)
I actually think it might be a sudo
issue now, because I previously had to run the Arduino IDE with sudo
for it to be able to access the ESP32's linker for some reason, but now I updated Arduino and I don't need sudo
for that anymore.
I don't want to run Arduino with sudo
because then it changes the owner of all the files to root
when I hit save and that is annoying. Do you know of any kind of rules I can add to my /etc/sudoers
that will allow avrdude to access USB ports?
First of all I would recommend Spence Konde's ATTinyCore rather than the much older David Mellis core.
I don't have any experience of using the Arduino IDE on Linux, but on Mac I have occasionally had some cases SparkFun programmer where the USB port seems to become unavailable, and I have to restart the Mac to cure it, or switch to the other USB socket.
or switch to the other USB socket.
Tried 'em all, none work.
Tried again with the Spence Konde core, same error.
You've tried restarting your computer?
Perhaps the ATtiny85 is damaged? Try another.
Re: AVR problems. I might be able to help if you give me a complete description of what you're doing.
A couple of other thoughts:
Have you used Burn Bootloader to change the fuses to choose a different clock setting? If you chose a setting using an external crystal, subsequent uploads will only work if you have the crystal present. You could plug one into the socket headers on the SparkFun programmer (don't worry about the capacitors; I've found it works OK on a prototyping board without them).
Have you selected a clock frequency lower than 1MHz? The upload may not work in this situation.
Both of these are documented on Spence Konde's README somewhere.
Perhaps the ATtiny85 is damaged? Try another.
I doubt that's the problem, because a) I bought then new, and have only reprogrammed this particular one like 6 times, and b) in the past I have made the mistake of forgetting to move the ATtiny85 from the breadboard to the programmer and it gave a different error, like "failed to read chip signature registers", not "cannot open USB device".
Have you used Burn Bootloader to change the fuses to choose a different clock setting? If you chose a setting using an external crystal, subsequent uploads will only work if you have the crystal present.
No, I only have ever used the default 8Mhz internal clock. (The internal clock is part of the reason I chose the ATtiny85 anyway!)
I never really have to reboot my computer, but I'll try that when I get home from school.
Unrelated to the ATtiny85 programmer issue:
I found this issue regarding the ESP32-C3 in particular timing out and getting confused by clock stretching. Maybe the plain ESP32 has the same bug.
The ESP32's Wire.cpp
source says the timeout is 50 milliseconds which should be more than enough, but all the arduino documentation says the number is in microseconds -- I'm going to try increasing the timeout to 50000 and seeing if that changes anything...
Update after rebooting computer:
ATtiny85 programmer still gives a "permission denied" error.
That's very odd. Can you think of anything else that might have changed since it last worked?
That's very odd. Can you think of anything else that might have changed since it last worked?
The only thing that changed is that I updated my Arduino IDE, and I'm not running it with sudo
anymore -- so I probably need to add avrdude to some permissions group or setting etc. because it isn't being run as root anymore. I don't have enough Linux experience to know what to do to fix that.
If that's the only thing that changed between it working and not working then that's probably the culprit.
Do you have an Arduino Uno (or equivalent)? Then you could try using that as an ISP programmer, as described here:
Do you have an Arduino Uno (or equivalent)? Then you could try using that as an ISP programmer, as described here:
I have an Uno. I thought of that, but honestly I don't think the programmer is at fault, it's my operating system.
I found this, a similar problem:
https://stackoverflow.com/questions/26421803/run-my-executable-automatically-as-root-ubuntu
Going to try that on avrdude and see if that fixes it...
I think the Sparkfun Programmer is doing something clever with the USB port, whereas using the UNO is just using the UNO's standard USB port device.
I found this, a similar problem:
https://stackoverflow.com/questions/26421803/run-my-executable-automatically-as-root-ubuntu
Going to try that on avrdude and see if that fixes it...
Sorry for the extremely late update... turns out it was a permissions problem. This worked!!
[/offtopic]
Good to hear!
I'm just going to close this now because it turns out it was a problem with the ATtiny85 that multi-byte reads didn't work (see https://github.com/SpenceKonde/ATTinyCore/issues/776). Sorry for all the unnecessary bother.
I've been playing around with the I2C bus on an ESP32 and connecting it to ATtiny85's emulating I2C slave devices. However, I'm having trouble figuring out how exactly to communicate with the I2C slave devices.
If it's relevant, I'm using this library to emulate an I2C slave, using the
requestEvent()
andreceiveEvent()
exactly as provided in the examples.I was able to read the registers write to them, and then read back the updated values using the raw
Wire
library commands in a non-uLisp sketch at the same time the Atiny was doing stuff with the value of the registers (the details are in this blog post of mine).I forgot about what I did there for a few weeks and uploaded a different Atiny sketch that didn't do anything at all but allow the master to read and write registers at will. I also figured out that the example code didn't do any bounds checking when receiving the target register address (specifically, this line), and could easily clobber over out-of-bounds memory, so I fixed it (by adding
% reg_size
) to the end of that line).Unfortunately, when I tried to read and write again with uLisp, it didn't work. The I2C port scanner got a successful ACK from the Atiny (on both the set address and address 0), but I only ever got 255's back when reading.
I don't have the code on hand right now, and I'm not sure what I did to fix the problem, but I eventually was able to read all the registers individually (i.e. write first register address, request+read 1 byte, write 2nd register address, request+read 1 byte, etc.), but not as one transaction (i.e. write register address, then request+read 4 bytes all at once) -- it sent the first register correctly but then just sent 255 for the rest of them.
I have a hunch that the Arduino
Wire
library, when you callrequestFrom
, it actually sends a byte to the slave device telling it that the master wants N bytes, rather than just restarting the transaction in read mode and reserving N bytes in the buffer -- which ends up confusing my Atiny which doesn't want to (or need to) know how many bytes will be requested in advance.I'll have to try again reading it with my Arduino Uno (where uLisp uses direct register manipulation, not the
Wire
library) and see if I get anything different.I'm not sure how to get around this problem -- what are your thoughts?