Перейти к содержанию

Когда нужна сотня UART’ов или примитивный драйвер для SC16IS740/SC16IS750/SC16IS760

Вот и наступил прекрасный момент, когда все доступные порты заняты, а битбэнгать как-то не сподручно. На сцену выходит микросхема-преобразователь UART в-из I2C/SPI

Есть аналоги подобных микросхем-преобразователей (MAX3107, MAX14830), которые скорей всего будут лучшим выбором, чем представленная выше. У них нет “магических” регистров доступа и FIFO длиннее. Так вышло, что под рукой была именно эта микросхема. Работа с доступом к определенным регистрам у нее очень специфичная.

Вот, например, сноски под описанием регистров из даташита:

Обратите внимание на п.п. 2, 7, 10 и 11. Такой выверт легко объяснить – под адресацию регистров микрухи разработчики заложили только 1 байт (16 адресов), а их понадобилось чуть больше.

Интересные дизайн-решения для этой микрухи были отмечены и разработчиками драйвера под Линукс:

Один неприятный момент заключается в том, что у микросхемы нет регистра с уникальным ID. Но зато у нее есть два регистра доступные для записи кастомных значений (Scratchpad Register (SPR)). Этот момент позволит нам определить – жива ли вообще микросхема на линии (если не доверять ASK по адресу)

А возможных адресов микросхемы целая коробка:

То есть, на один интерфейс I2C можно посадить до 16 UART’ов (если не брать в расчет расширители I2C). Да, достаточно низкоскоростных, но, вполне функциональных. При подключении по SPI, мы вообще ограничены только количеством ножек под CS (если не брать в расчет расширители портов)

Для работы с этой микрухой была написана примитивная, портируемая библиотека на голом Си.

Если FIFO не используется надо закомментить это в коллбэк-функции:

    	//fifo_len = SC16_read_register(SC16IS7XX_RXLVL);
    	//while (fifo_len--){
    		data = SC16_RX();
    		get_data(data);
    	//}

По-умолчанию, включен FIFO, прерывания на RX линии и классические 8 бит, без четности и 1 стоп-бит. Эти настройки можно изменить тут (или дописать свои функции):

SC16_write_register(SC16IS7XX_FCR,  0x01);   //enable fifo
SC16_write_register(SC16IS7XX_IER,  0x05);  //enable Rx data ready, lsi interrupt
SC16_write_register(SC16IS7XX_LCR, 0x03); // 8 data bit, no parity (add "| SC16_2STOPBITS" to 2-stopbits support)

Если не использовать прерывания, то можно бесконечно опрашивать этой функцией

uint8_t SC16_is_data_aval(void)

Если нужно опрашивать/писать_в много таких микрух (действительно нужна сотня) на одной линии с разными адресами, то стоит подумать над созданием структуры объекта микросхемы расширителя, указатель на который можно будет передавать как параметр каждой функции.

Использование драйвера: Функция SC16_interrupt_callback(void) должна вызываться в цикле или при внешнем прерывании от микросхемы SC16IS7XX. Функции i2c_write(uint8_t addr, const uint8_t *data, int len), i2c_read(uint8_t addr, uint8_t *data, int len) и get_data(uint8_t data) должны быть определены для вашей целевой платформы.

Пример для STM32 и HAL:

#define ARR_SIZE 8
static uint8_t my_best_array[ARR_SIZE] = {0};
static uint8_t array_pointer = 0;

HAL_StatusTypeDef i2c_write_ext(uint8_t addr, const uint8_t *data, int len)
{
    HAL_StatusTypeDef status;
    status = HAL_I2C_Master_Transmit(I2C_EXT_ADDR, addr, (uint8_t*)data, len, 0x05);
    return status;
}

HAL_StatusTypeDef i2c_read_ext(uint8_t addr, const uint8_t *data, int len)
{
    HAL_StatusTypeDef status;
    status = HAL_I2C_Master_Recieve(I2C_EXT_ADDR, addr, (uint8_t*)data, len, 0x05);
    return status;
}

void get_data(uint8_t data){
    my_best_array[array_pointer] = data;
    array_pointer++;
}

Для вашего устройства необходимо изменить частоту генератора микросхемы SC16IS7XX X_TALL_FREQ и адрес микросхемы I2C_EXT_ADDR.

При использовании скорости I2C в 100кГц и длинных пачек данных через UART на 115200 бод, внутренний FIFO микросхемы может быстро переполняться. Короткие посылки передаются вполне хорошо даже на такой скорости.

Ссылка на GitHub:

Comment

programel