Go Down

Topic: Non-Blocking I2C using DMAC (Read 7242 times) previous topic - next topic

Koepel

A software I2C on the ATmega has 40 mA pull down current, and I have heard no complains yet. Therefor the 10 mA should be fine.
When long wires are used for SDA and SCL, a 3 mA pulldown current and the filter might help a little. I think the maximum length of the wires will not be twice as long compared to the SAMD without those things.

The SAMD51 is an amazing processor 8) I have been reading about it in the last hours. Adafruit tells to wait until November because the SAMD51 they want is not available yet.

The templates use what the compilers knows. It is straightforward... until using arrays. I have already some changes in mind.

I can't even solder normal smd, but Eevblog as a few videos about soldering. Either with a soldering iron and a lot of flux or reflow soldering: https://www.youtube.com/watch?v=M_rO6oPVsws

dlabun

FYI: That was November 2017 they were talking about for the SAMD51s.... It seems the supply constraints have eased as a lot of distributors are stocking the SAMD51 chips now. I don't know the status for the SAMD51 boards from Adafruit, but if you look at their Github repository you'll see they're actively working on the Arduino core.


MartinL

#33
Apr 13, 2018, 09:59 am Last Edit: Apr 13, 2018, 10:00 am by MartinL
Good news, Thanks for the link.

Also, looks like Adafruit are going back to the SAMD51x20A with 1MByte flash, 256KByte RAM that they originally intended to use.

(They had switched over to the 512KBytes flash and 192KBytes RAM in their SAMD51 core code).

rsonnicksen

I will readily admit that much of this is over my head as I'm fairly new to the Arduino, but I'm also trying to use an MPU6050 in an Arduino Uno based flight controller, and would like to use non-blocking I2C reads to get the accel and gyro data.  I do not understand all of the references to SERCOM3 and DMAC.
I have read through the Atmel ATmega-328P data sheet (Uno microcontroller) and am really missing what's going on here.  Does the Arduino Zero have some hardware capability that the Uno doesn't, or what am I missing.  I would really like to be able to do this (non-blocking reads).

Thanks,
Newbie Randy

Koepel

The Arduino Uno has little benefits with a non-blocking I2C library. It is only running at 16 MHz.

The Arduino Uno uses the ATmega328P, which is a microcontroller that can turn a led on and off. It does not even have flexible hardware like the USI (in some ATtiny chips) or SERCOM (in ARM processors) and it has no DMA.

The Arduino Zero uses a ARM processor, which can do a lot more than the ATmega chips, allthough it can not run a full operating system.

When you are new to Arduino and you need a faster Arduino board... that might not always help. Sometimes the code has a lot delay() in it or useless waiting for nothing. In such a situation a faster Arduino board will be just as slow.

MartinL

#36
Apr 28, 2018, 05:23 pm Last Edit: Apr 28, 2018, 05:26 pm by MartinL
The Adafruit Metro M4 (SAMD51) is now available, but the first batch has currently sold out: https://www.adafruit.com/product/3382.

I was wrong, looks like the Metro M4 is using the 512KByte flash, 192KByte RAM variant after all, but it also comes with 2MB QSPI flash storage chip.

The SAMD51 is a nice micro-controller and will be strangely familiar to anyone who currently uses the SAMD21.

MartinL

#37
Sep 04, 2018, 01:01 pm Last Edit: Sep 04, 2018, 01:08 pm by MartinL
I've updated the I2C_DMAC library to version 1.1.6 on Github.

I made a small change to allow the I2C.begin() function to specify that the I2C port is using the SERCOM_ALT (alternative SERCOM) peripheral. This is nessesary for compatibility with the Adafruit Metro M4 board, whose default I2C port uses SERCOM5 on SERCOM_ALT.

If you're using the library with the Metro M4, then just call the begin() function with the following arguments, (400kHz, 8-bit register addressing, alternative SERCOM peripheral):

Code: [Select]
I2C.begin(400000, REG_ADDR_8BIT, PIO_SERCOM_ALT);
Or with REG_ADDR_16BIT if you're using 16-bit addressing.

The Adafruit Feather M4 and Itsy Bitsy M4 are unaffected, as their default I2C port uses the primary SERCOM peripheral.

svdbor

Can this library be used to create a slave device version of the SAMD51 (M4)? I tried the regular wire library to communicate between two SAMD51 devices, but the master locks up. Will be great to implement the DMAC wire library as an alternative instead.

MartinL

Hi svdbor,

Quote
Can this library be used to create a slave device version of the SAMD51 (M4)?
Unfortunately it doesn't. The I2C_DMAC library currently only supports the Arduino/Metro as the master.

standarddeviant

MartinL,

Firstly, thank you so much for writing this wonderful library!  :)

I have a question regarding the API and capabilities. My situation is that I have a MKR1000 and want to pull data from two different IMUs connected to the same I2C bus/pins: GPIO pins 11 and 12 for SDA and SCL respectively.

Can I use I2C_DMAC to...

1. schedule reading accel from accel1 on i2c address1
2. run concurrent code and wait for accel1
3. read accel1 results

4. schedule reading accel from accel2 on i2c address2
5. run concurrent code and wait for accel2
6. read accel2 results

7. go back to step 1 and repeat the process

I noticed that there's an example that uses two separate I2C interfaces, but I want to use one I2C interface to communicate to multiple IMUs as I2C slaves.

Thanks in advance!

MartinL

#41
Apr 17, 2019, 01:29 pm Last Edit: Apr 17, 2019, 02:59 pm by MartinL
Hi standarddeviant,

Quote
Can I use I2C_DMAC to...

1. schedule reading accel from accel1 on i2c address1
2. run concurrent code and wait for accel1
3. read accel1 results

4. schedule reading accel from accel2 on i2c address2
5. run concurrent code and wait for accel2
6. read accel2 results

7. go back to step 1 and repeat the process
Yes, it's possible to read and write from multiple IMU sensors using a single I2C port.

Communicating with multiple sensors just requires to DMA descriptors to be reloaded with the each time you switch sensor. This is done for you automatically using a combined write/read with the readBytes() function, for example:

Code: [Select]
I2C.readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, &data[0], 14);   // Read the gyroscope, accelerometer and temperature
// Add concurrent code here...
while(I2C.readBusy);     // Wait for synchronization

...or, separating out the write and the read:

Code: [Select]
I2C.writeRegAddr(MPU9250_ADDRESS, ACCEL_XOUT_H);    // Set the sub address to the ACCEL_XOUT_H register
// Add concurrent code here...
while(I2C.writeBusy);                              // Wait for synchronization
I2C.readBytes(MPU9250_ADDRESS, &data[0], 14);    // Read the gyroscope, accelerometer and temperature
// Add concurrent code here...
while(I2C.readBusy);     // Wait for synchronization

If on the other hand you're just using a single sensor then it isn't necessary to reload the DMA descriptors each time. In this case its possible set up the DMA descriptors only once:

Code: [Select]
I2C.initWriteRegAddr(MPU9250_ADDRESS, ACCEL_XOUT_H);
I2C.initReadBytes(MPU9250_ADDRESS, &data[0], 14);

...then simply read the data each time using:

Code: [Select]
I2C.write();   // Set the sub address to the ACCEL_XOUT_H register
// Add concurrent code here...
while(I2C.writeBusy);    // Wait for synchronization
I2C.read();   // Read the gyroscope, accelerometer and temperature
// Add concurrent code here...
while(I2C.readBusy);  // Wait for synchronization

standarddeviant

MartinL,

I understand the API much better now! This is very helpful. Thank you again and it is obvious why your Karma on this forum is so high. :-)

Many thanks,
standarddeviant

Go Up