I2C on SAMD21 with Atmel Start works only in one direction

I am trying to establish a half-duplex I2C communication between two ATSAMD21G18A microcontrollers, using Atmel Start’s I2C functionality. (HAL Synchronised I2C)

The automatically generated example files include only a write example on master, and only a read example on slave. I figured that I can use same function calls to do vice versa: writing from slave and reading at master.

However, while the code works perfectly fine if master writes to slave, if I modify the code so that slave writes to master, it behaves … unpredictably. Occasionally it appears to work, sometimes sends garbage, and mostly 255. After a few seconds, slave MCU freezes completely, no longer drives the bus and remains so until a power cycle. In the mean time, master MCU remains functional.

I am not sure if I am missing something obvious, maybe even in general for I2C. Example codes and my codes are given below. And few key points are as such:

  • Actual read and write functions are, of course, different in master and slave devices, in the codes below, the same io_write and io_read functions point to different functions i2c_m_sync_write (master) and i2c_s_sync_write (slave) and so on, at the background.
  • I cannot really post actual functions that does the work, because there are 6 functions that sequentially call each other, for no apparent good reason. If I were to copy-paste them here, entire question would turn into an unintelligible mess.
  • For the life of me I cannot do proper debugging because Microchip’s IDE flips me off and tells me that it failed to load .elf file. I have failed to solve this problem for months now. Therefore I cannot tell if the program gets stuck on an infinite loop somewhere, waits something or gets unrecoverably corrupted.

The fact that it works master to slave as provided on the examples fine, but not in the other way around, makes me hope that there is something trivial and obvious that I missed. In any case, any help or suggestions will be appreciated.


Provided write example on master device:

void I2C_0_example( void )
{
    struct io_descriptor *I2C_0_io;

    i2c_m_sync_get_io_descriptor( &I2C_0, &I2C_0_io );

    i2c_m_sync_enable( &I2C_0 );
    i2c_m_sync_set_slaveaddr( &I2C_0, 0x12, I2C_M_SEVEN );

    io_write(I2C_0_io, (uint8_t *)"Hello World!", 12);
}

Provided read example on slave device

void I2C_0_example(void)
{
    struct io_descriptor *io;
    uint8_t               c;

    i2c_s_sync_get_io_descriptor( &I2C_0, &io );

    i2c_s_sync_set_addr( &I2C_0, 0x12 );
    i2c_s_sync_enable( &I2C_0 );

    io_read( io, &c, 1 );
}

Based on which, I wrote:

For the Master:

uint8_t slavedata[ 64 ] = { 0 };

for ( ;; )
{
    // attemps to read from the slave device
    memset( slavedata, 0, sizeof slavedata);
    if ( io_read( io, slavedata, sizeof slavedata) == sizeof slavedata )
    {
        usb_serial_puts( slavedata);
        usb_serial_puts( "rn" );
    }
    // yes, io_read returns the passed size argument back if it succeeds,
    // not the number of characters it actually read.
}

For the slave:

    uint8_t data[ 64 ] = { 0 };

    for ( ;; )
    {       
        // populates the `data` array.
        // example str: "0.000 0.000 0.000 0.000", null terminated
        // format remains same all the time, values change. 
        memset( data, 0, sizeof data );
        read_to_str( data, sizeof data );
        
        // same as the example, only difference is this device is a slave device.
        io_write( io, selfdata, sizeof selfdata );
        
        // prints to a terminal over uart. 
        usb_serial_puts( "Sent: " );
        usb_serial_puts( data );
        usb_serial_puts( "rn" );
    }

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật