Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Траблы с контроллером IIC от Xilinx
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Koluchiy
Здравствуйте, уважаемые гуру.

Имеем девайс IIC (датчик температуры), висящий на Kintex 7.
Все это подключается к стандартному контроллеру IIC в XPS и Microblaze.

И вроде как все оно работает, НО.
Если попробовать сделать обмен типа "прочитать температуру":
1. Записать адрес датчика температуры
2. Записать регистр датчика температуры (0 - MSB темперетары)
3. Repeated Start
4. Записать адрес датчика температуры
5. Прочитать температуру
6. Стоп

То до п. 4 включительно все нормально, а потом контроллер IIC вылетает с ошибкой "потеря арбитража".
При этом, если вместо "Repeated Start" поставить "Stop", а затем "Start", то все нормально работает.

Внимание, вопрос: кто-нибудь сталкивался с подобным?
Какие могут быть причины, и как бороть?

Соединение точка-точка, никаких других мастеров на этой шине нет. Датчик мастером быть не умеет и не пытается. На Чипскопе и осцилле до п. 4 включительно все выглядит как надо.

Всем заранее спасибо за помощь.
MadGarry
Попробуйте поменять антиглитчевые задержки. Когда-то и где-то видел задержку SDA относительно SCL но в приложенной картинке этой задержки нет.
Koluchiy
Пробовал, не помогает.
alexadmin
Я долго бился со стандартным API, но оно меня в итоге победило (точно так же зависало в процессе). В конце концов я написал вручную две функции доступа, немного пошаманил, помухлевал и в итоге работает, хотя тут тоже есть нюансы.

Код
// Simple user-created API to IIC controller
// http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Why-the-IIC-can-t-be-stopped/td-p/295693
u32 iic_write(u32 baseaddr, u32 daddr, u32 waddr, u32 wdata) {
    int stat2;
    u32 timeout;
    int stat = (Xil_In32(baseaddr + 0x104));
    if(stat != 0xc0)
    {
    //    print("Bad stat.");
        Xil_Out32((baseaddr + 0x100), 0xc0|0x02); // reset tx fifo
//        Xil_Out32((baseaddr + 0x100), 0xc0|0x03); // enable iic
    }
    Xil_Out32((baseaddr + 0x100), 0xc0|0x00); // disable iic
    Xil_Out32((baseaddr + 0x100), 0xc0|0x01); // enable iic

    Xil_Out32((baseaddr + 0x100), 0xc0|0x0d); // Start; Transmit
    Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write
    Xil_Out32((baseaddr + 0x108), waddr); // send register address
    Xil_Out32((baseaddr + 0x108), (0x200 | (wdata & 0xFF))); // send data byte with stop bit
    timeout = 100; // timeout
    while(1)    // ToDo: add timeout to avoid hang up when I2C slave is not responding (no ACK)
    {
        stat2 = Xil_In32(baseaddr + 0x104);
        // wait for TX FIFO empty
        if( ((stat2 & 0x80) ) && ((stat2 & 0x04)== 0) )    // TX FIFO empty && Bus not busy
            break;
        if (timeout == 0) {
            xil_printf("iic write timed out %x %x\n\r", waddr, wdata);
            return 0xFFFFFFFF; // data not valid
        }
        timeout--;
        usleep(200);
    }
    return 0;
}


u32 iic_read(u32 baseaddr, u32 daddr, u32 raddr) {
    int stat2;
    u32 rdata, timeout;
    int stat = (Xil_In32(baseaddr + 0x104));
    if(stat != 0xc0)
    {
    //    print("Bad stat.");
        Xil_Out32((baseaddr + 0x100), 0x002); // reset tx fifo
        Xil_Out32((baseaddr + 0x100), 0x003); // enable iic
    }
    Xil_Out32((baseaddr + 0x100), 0x000); // disable iic
    Xil_Out32((baseaddr + 0x100), 0x001); // enable iic

    Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write
    Xil_Out32((baseaddr + 0x108), raddr); // send register address
    Xil_Out32((baseaddr + 0x108), (0x101 | (daddr & 0xFE))); // send slave address for read
    Xil_Out32((baseaddr + 0x108), 0x201); // set stop after 1 data byte
    timeout = 100; // timeout
    while(1)
    {
        stat2 = Xil_In32(baseaddr + 0x104);
        if ((((stat2 & 0x40) == 0x0)) || (timeout == 0)) // (RX FIFO not empty && Bus not busy) or timeout    //  && ((stat2 & 0x04)== 0)
            break;
            //(((Xil_In32(IIC_BASEADDR + 0x104) & 0x40) == 0x40) && (timeout != 0)) { // wait for read FIFO not empty
        timeout--;
        delay_ms(1);
    }
    rdata = Xil_In32(baseaddr + 0x10C) & 0xFF; // read data byte
    delay_ms(1);
    if (timeout == 0) {
        xil_printf("iic read timed out %x %x\n\r", raddr, rdata);
        return 0xFFFFFFFF; // data not valid
    }
    return (rdata);
}

Koluchiy
Если читать Ваши комментарии так, как они написаны, то после записи адреса регистра Вы делаете стоп. Мне надо добиться, чтобы работал Repeated start, т.е. без стопа между записью номера регистра и чтением данных.
alexadmin
Цитата(Koluchiy @ Feb 19 2014, 12:27) *
Если читать Ваши комментарии так, как они написаны, то после записи адреса регистра Вы делаете стоп. Мне надо добиться, чтобы работал Repeated start, т.е. без стопа между записью номера регистра и чтением данных.


Где?

Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write
Xil_Out32((baseaddr + 0x108), raddr); // send register address

Вот тут идет рестарт с отправкой физического адреса устройства
Xil_Out32((baseaddr + 0x108), (0x101 | (daddr & 0xFE))); // send slave address for read

А теперь идет чтение (в данном случае одного байта) и после этого стоп
Xil_Out32((baseaddr + 0x108), 0x201); // set stop after 1 data byte
Koluchiy
Извиняюсь, был неправ.

Да, вроде работает sm.gif.
Спасибо!
Koluchiy
Ах да, в итоге прицепил контроллер с Opencores (тот самый, который Altera рекомендует).
Koluchiy
...И тут выяснилось, что этот контроллер только мастер...
Граждане, понасоветуйте культурный I2C slave контроллер (с исходниками желательно на Verilog), чтобы к процессору хорошо цеплялся и библиотеки на Си чтоб были sm.gif.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.