Stm32 + 1-wire + DMA


Введение
Сначала чуть освежим принципы работы с 1-wire через USART.Схема подключения — проста как три копейки. В качестве подопытного будет выступать термометр DS1820. Да, знаю что лучше было бы взять DS18b20, но что под руку попалось…

Reset выполняется так — настройки порта 9600,8,n,1, отправляем 0xf0, если приходит не 0xf0 – значит на линии кто-то сидит.
Для всех остальных действий настройки порта 115200,8,n,1
Запись 0 — отправляем 0х00. По идее и прийти должно 0x00
Запись 1 — отправляем 0хff. По идее и прийти должно 0xff
Чтение — отправляем 0xff. Если вернулось 0xff – прочиталась 1, иначе — 0.
Соответственно, чтобы записать байт на линию 1-wire, нам надо прокачать 8 байт через USART. Вручную это делать неинтересно, почитаем, что нам пишут про DMA. Как это примерно выглядит — формируем буфер для отправки, настраиваем DMA (указываем сколько, откуда, и куда заслать), даем пинка и все завертелось.
У STM32F103 есть два контроллера DMA, в сумме 12 каналов. Каждый канал закреплен за своей периферией. Ну и кроме того, любой канал может работать в режиме память-память, но нам такой режим пока не интересен.
Раскладка каналов по периферии приведена в Reference manual, в разделе про DMA. Нас интересует строка UART. Исторически сложилось, что я в примере использовал USART2, значит для него задействуем каналы DMA1_Channel6 и DMA1_Channel7


Инициализация
И первый шаг — инициализация:void OW_Init(USART_TypeDef* USARTx) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStructure;
if (USARTx == USART2) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
}
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USARTx, &USART_InitStructure);
USART_Cmd(USARTx, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
Как такой поток сознания написать быстро и не запутавшись? У католиков есть мнемоника, чтобы запомнить как креститься — «очки, яйца, бумажник, часы». У нас немного по-другому «часы, ноги, периферия»:
Первой командой включаем тактирование порта GPIOA. Почему A? Потому что там находятся ноги USART2. Смотреть распиновку в даташите.
Потом настраиваем ноги. Про это надо читать в разделе General-purpose and alternate-function I/Os (GPIOs and AFIOs). Там есть таблички на все случаи жизни, в том числе и USART. Ногу TX ставим в альтернативный пуш-пул, ногу RX — оставляем висеть.

И дальше включаем периферию. В нашем случае USART и DMA1.
Сброс шины 1-wire
Едем дальше — Reset.uint8_t OW_Reset(USART_TypeDef* USARTx) {
uint8_t ow_presence;
USART_InitTypeDef USART_InitStructure;
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USARTx, &USART_InitStructure);
USART_ClearFlag(USARTx, USART_FLAG_TC);
USART_SendData(USARTx, 0xf0);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
ow_presence = USART_ReceiveData(USARTx);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USARTx, &USART_InitStructure);
if (ow_presence != 0xf0) {
return 1;
}
return 0;
}
Тут вроде все должно быть понятно — устанавливаем 9600, шлем байт, ждем отправки, читаем что на шине и устанавливаем скорость обратно 115200.
Можно было бы задействовать прерывание, но я буду использовать freeRTOS, поэтому мне проще будет отдать тик системе, чтобы она провернула другую задачу, чем возиться с прерываниями. В чем прелесть работы с 1-wire через USART, это то, что все тайминги внутри слота чтения/записи выдерживает USART аппаратно, а задержки между битами никого не волнуют, хоть на год растянется. Поэтому если мы и пропустим пару микросекунд, ничего нам за это не будет.
Ну и флаг анализирую USART_FLAG_TC – Transfer Complete. Этот флаг означает что все, данные уехали в шину полностью. Казалось бы, есть еще флаг USART_FLAG_TXE, но он означает, что всего лишь освободился регистр данных, а сами данные еще перемалываются в дебрях USART. Как банкомат, который карточку уже сожрал, а денег еще не дал. А нам кроме того, что отправить данные, надо еще и прочитать, что же в итоге наших манипуляций получилось. Поскольку выход TX и вход RX жестко связаны по схеме, то в момент окончания отправки чудесным образом у нас закончится прием байта. И его можно будет считать командой USART_ReceiveData().
Функция OW_Reset() в итоге возвращает 0 — если никаких устройств на шине не откликнулось и дальнейший обмен бесперспективен, или 1 — в противном случае.
Посылка команд
Теперь самое интересное — посылка пакета команд.
Как, например, выглядит работа с термометром? Посылаем ему сначала команду выбора «эй, ты!», ну или «эй вы все, слушать сюда». Потом посылаем собственно команду «температуру измеряй!». Для примера я не буду задействовать идентификатор устройства, а буду кричать всем.
Нам надо отправить два байта 0xcc (SKIP ROM) и 0x44 (CONVERT T). При этом через USART надо будет прокачать 16 байт. Создадим соответствующий массив:
#define OW_0 0x00
#define OW_1 0xff
#define OW_R 0xff
const uint8_t convert_T[] = {
OW_0, OW_0, OW_1, OW_1, OW_0, OW_0, OW_1, OW_1, // 0xcc SKIP ROM
OW_0, OW_0, OW_1, OW_0, OW_0, OW_0, OW_1, OW_0 // 0x44 CONVERT
};
В 1-wire биты передаются начиная с младшего, поэтому записываем их наоборот.
Дальше вызываем функцию:
void OW_SendCommand(USART_TypeDef* USARTx, const uint8_t *command, uint16_t len) {
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = len;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel7, ENABLE);
}
Настройку DMA разберем подробнее:
В качестве адреса периферии устанавливаем адрес регистра данных USART2
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
В качестве адреса памяти берем переданный в параметрах массив — его мы составляли ранее.
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;
Направление передачи — из памяти в периферию
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
Длина передаваемого блока данных. Не может превышать 65536 байт.
DMA_InitStructure.DMA_BufferSize = len;
Надо ли увеличивать адрес порта после каждой передачи? Нет не надо — все льем в один порт
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
Надо ли увеличивать адрес памяти? Надо конечно, нам весь буфер передать надо.
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
Ширина данных — по одному байту.
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
Режим работы — обычный (есть еще кольцевой)
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
Приоритет — низкий
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
Отключен режим память-память
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
Вот эта команда говорит — USART2, еси тебе нечего передавать, дергай DMA, он тебе еще отсыплет. Канал DMA не указывается, он и так понятен какой — DMA1_Channel7.
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
Ну и запуск DMA.
DMA_Cmd(DMA1_Channel7, ENABLE);
После того, как запустили DMA, он первым делом закинет первый байт, а дальше уже USART будет его дергать. Поэтому порядок инициализации именно такой — сначала USART_DMACmd, а только потом — DMA ENABLE.
В даташите сказано — как только закончите пользоваться, сразу сделайте
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);
Ну а поскольку мы никакой активности в порту USART не ожидаем, да и следующая команда будет гарантированно RESET, то засунем эту команду в начало функции OW_Reset().
Чтение данных
Это если нам не надо ничего читать из устройств 1-wire. А что делать, если они нам будут слать что-то? Надо подключить второй канал DMA, ну и вдобавок определить буфер, куда мы будем все считывать.
const uint8_t read_scratch[] = {
OW_0, OW_0, OW_1, OW_1, OW_0, OW_0, OW_1, OW_1, // 0xcc SKIP ROM
OW_0, OW_1, OW_1, OW_1, OW_1, OW_1, OW_0, OW_1, // 0xbe READ SCRATCH
OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R,
OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R
};
uint8_t scratch[sizeof(read_scratch)];
void OW_ReadData(USART_TypeDef* USARTx, const uint8_t *command, uint8_t *buf, uint16_t len) {
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = len;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = len;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel6, ENABLE);
DMA_Cmd(DMA1_Channel7, ENABLE);
while (DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET);
}
Тут инициализируется канал 6 первого контроллера. Из отличий:
В качестве адреса памяти используется выделенный буфер
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) buf;
И направление немного другое — из периферии в память
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
Соответственно команда USART'у будет такой:
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
Типа отправляй как в прошлом примере, но если чего-то принял, то тоже дергай DMA.
Тут я просто ожидаю окончания работы с DMA. Опять же, можно использовать прерывание, благо их много есть у нас — и по исчерпанию половины буфера, и по полному завершению передачи. Но, повторюсь, я лучше тик отдам системе.
while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET);
main.c
Как теперь этим пользоваться?
OW_Init(OW_USART);
OW_Reset(OW_USART);
OW_SendCommand(OW_USART, convert_T, sizeof(convert_T));
for (i=0; i<1000000; i++);
OW_Reset(OW_USART);
OW_ReadData(OW_USART, read_scratch, scratch, sizeof(read_scratch));
uint16_t tt=0;
for (i=16;i<32; i++) {
if (scratch[i] == 0xff) {
tt = (tt>>1) | 0x8000;
} else {
tt = tt>>1;
}
}
Задержка после команды Convert T – это время на измерение температуры. Читать в даташите на датчик.
По результатам действия в переменной tt будет значение первых двух байт из scratch-памяти термометра. Это и есть температура.
Выводы
Пока в виде готовой библиотеки не выкладываю, обкатаю в проекте, посмотрю во что выльется.
Поиск устройств особо не распараллелишь, он интерактивный на каждом шаге. Придется делать как в OW_Reset – кинули байтик, ждем.
Минус один — требуется буфер, достаточно большой.
Но можно минус слегка нивелировать — в этом буфере составлять команду и в него же читать передаваемые данные. Посмотрим.
UPD. Вот ссылка на пост с оформленной библиотекой:
http://we.easyelectronics.ru/STM32/stm32-1-wire-dma-prodolzhenie.html

- +6
- 11 февраля 2012, 00:57
- steel_ne
Гм. Я бы спихнул формирование массивов из OW_x на библиотеку. Тогда будет функция вида uint8_t OW_SendByte(uint8_t Data), использующая 16 байт под внутренние буферы (8 на передачу, 8 на прием), и принимающая/выдающая данные сразу удобоваримым байтиком.
А вообще, буфер можно один использовать. Все равно, когда пришел на RX очередной байтик — это значит, что из буфера передачи он уже забран и больше не нужен. Так что можно оба канала натравить на один буфер.
А вообще, буфер можно один использовать. Все равно, когда пришел на RX очередной байтик — это значит, что из буфера передачи он уже забран и больше не нужен. Так что можно оба канала натравить на один буфер.
Хотелось сначала сформировать всю посылку, а потом ее выплюнуть. По большому счету часть команд — это константы. Например, начало измерения температуры, запись в скретч (конфигурация датчика). В другой части команд будет использоваться восьмибайтный айди датчика, вот как там соберется команда — не знаю.
А про оба канала на один буфер — это реально.
А про оба канала на один буфер — это реально.
На лифлабсовском форуме как раз всплыла аналогичная тема, запостил линк на статью туда. Кстати, нет желания/возможности перевести статью на английский? Думаю, желающих почитать ее в таком виде найдется немало.
P.S. вот бы тоже самое, но на libmaple…
P.S. вот бы тоже самое, но на libmaple…
Та как-то не тусовался на зарубежных форумах. А лифлабс нормальный по контингенту?
А что такое вообще libmaple? :)
А что такое вообще libmaple? :)
Да, вполне. Только активность там не очень высокая.
P.S. www.leaflabs.com и дальше по ссылкам, там и форум, и Maple, и libmaple. Еще стоит глянуть github.com/gbulmer/openstm32sw и github.com/gbulmer/openstm32hw.
P.S. www.leaflabs.com и дальше по ссылкам, там и форум, и Maple, и libmaple. Еще стоит глянуть github.com/gbulmer/openstm32sw и github.com/gbulmer/openstm32hw.
По поводу перевода: я могу помочь, если есть необходимость.
P.S. как минимум еще двое людей из местного сообщества периодически тусуются на лифлабсе.
P.P.S. любопытно, будет ли DIHALT против постов на других языках или, например, комбинированных постов, где текст присутствует более чем на одном языке…
P.S. как минимум еще двое людей из местного сообщества периодически тусуются на лифлабсе.
P.P.S. любопытно, будет ли DIHALT против постов на других языках или, например, комбинированных постов, где текст присутствует более чем на одном языке…
Я заметил, что если этот термометр опросить сразу после включения и продолжать опрашивать ~раз в секунду, то через 5-10 секунд он показывает на 0,5-1 градуса больше, чем сразу после включения. Нагревается что-ли сам от себя. С таким раскладом точности в 1/16 градуса доверять нельзя (( По хорошему, 1/2 градуса — это максимум, на что он способен. А не знает ли кто-то более точного термометра?
- phantom_lord
- 27 марта 2012, 13:59
- ↓
Не знаю насчет этого, а вот в даташите на SHT21 прямо сказано — при скважности работы более 10% (т.е. опрос чаще 1 Гц при максимальной точности преобразования — оно при этом занимает 100мс) микросхема разогревается.
Кроме того, не надо забывать про детали рядом с термометром. Этому Sensirion даже отдельный документ посвятили. Не зря датчик на демоплатах отгорожен от прочей платы прорезью в текстолите.
Кроме того, не надо забывать про детали рядом с термометром. Этому Sensirion даже отдельный документ посвятили. Не зря датчик на демоплатах отгорожен от прочей платы прорезью в текстолите.
Поправьте меня если я ошибаюсь.
Если сконфигурировать выход USART_TX как open drain, то можно исключиь диод из схемы.
В даташите как раз указанно, что USART_TX может быть как PushPull так и OpenDrain.
Если сконфигурировать выход USART_TX как open drain, то можно исключиь диод из схемы.
В даташите как раз указанно, что USART_TX может быть как PushPull так и OpenDrain.
Проглядел даташит, не нашел такого. Я писал для серии STM32F103. Может на STM8, например, и допустима такая гибкость.
Как раз для STM32F103
Кстати, у меня валяется ещё этот документ 11 ревизии, так там действительно нет этой сноски :)
Вчера попробовал сконфигурировать USART_TX как OpenDrain и убрал диод, всё работает замечательно.
ЗЫ: Вообще статья отличная, она мне очень помогла, спасибо.
The USART_TX pin can also be configured as alternate function open drain.Страница 162 Reference Manual Rev 14
Кстати, у меня валяется ещё этот документ 11 ревизии, так там действительно нет этой сноски :)
Вчера попробовал сконфигурировать USART_TX как OpenDrain и убрал диод, всё работает замечательно.
ЗЫ: Вообще статья отличная, она мне очень помогла, спасибо.
Спасибо, буду знать. Скорее всего я сам и напоролся на классику — читай последний даташит, а не тот, который есть ))
вопрос по количеству ног… типа 1-wire, так 1-wire
ткните носом, может я чего-то не понял во всей химии, но внутреннее соединение TX c RX и OpenDrain в одном флаконе:
RM0008 Doc ID 13902 Rev 14 стр 779
27.3.10 Single-wire half-duplex communication
The single-wire half-duplex mode is selected by setting the HDSEL bit in the USART_CR3
register. In this mode, the following bits must be kept cleared:
● LINEN and CLKEN bits in the USART_CR2 register,
● SCEN and IREN bits in the USART_CR3 register.
The USART can be configured to follow a single-wire half-duplex protocol. In single-wire
half-duplex mode, the TX and RX pins are connected internally. The selection between halfand
full-duplex communication is made with a control bit ‘HALF DUPLEX SEL’ (HDSEL in
USART_CR3).
As soon as HDSEL is written to 1:
● RX is no longer used,
● TX is always released when no data is transmitted. Thus, it acts as a standard IO in idle
or in reception. It means that the IO must be configured so that TX is configured as
floating input (or output high open-drain) when not driven by the USART.
Apart from this, the communications are similar to what is done in normal USART mode.
The conflicts on the line must be managed by the software (by the use of a centralized
arbiter, for instance). In particular, the transmission is never blocked by hardware and
continue to occur as soon as a data is written in the data register while the TE bit is set.
Платы нет, железки нет — типа готовлюсь теоретизирую…
Наткнулся играясь с MicroXplorer 2.1
ткните носом, может я чего-то не понял во всей химии, но внутреннее соединение TX c RX и OpenDrain в одном флаконе:
RM0008 Doc ID 13902 Rev 14 стр 779
27.3.10 Single-wire half-duplex communication
The single-wire half-duplex mode is selected by setting the HDSEL bit in the USART_CR3
register. In this mode, the following bits must be kept cleared:
● LINEN and CLKEN bits in the USART_CR2 register,
● SCEN and IREN bits in the USART_CR3 register.
The USART can be configured to follow a single-wire half-duplex protocol. In single-wire
half-duplex mode, the TX and RX pins are connected internally. The selection between halfand
full-duplex communication is made with a control bit ‘HALF DUPLEX SEL’ (HDSEL in
USART_CR3).
As soon as HDSEL is written to 1:
● RX is no longer used,
● TX is always released when no data is transmitted. Thus, it acts as a standard IO in idle
or in reception. It means that the IO must be configured so that TX is configured as
floating input (or output high open-drain) when not driven by the USART.
Apart from this, the communications are similar to what is done in normal USART mode.
The conflicts on the line must be managed by the software (by the use of a centralized
arbiter, for instance). In particular, the transmission is never blocked by hardware and
continue to occur as soon as a data is written in the data register while the TE bit is set.
Платы нет, железки нет — типа готовлюсь теоретизирую…
Наткнулся играясь с MicroXplorer 2.1
Господа! Вопрос такой. Меня смущает вот это: "
Точно не погорит, например, через полгодика-годик работы, если без диода?
Может у кого-нибудь есть схема готовая, чтобы быстро попробовать слать в UART в half duplex? А подтягивающий к питанию резистор заменить на подтягивающий к земле — сразу будет видно, open drain или нет.
It means that the IO must be configured so that TX is configured as floating input (or output high open-drain) when not driven by the USART". А когда управляется UART-ом, значицца, совсем не обязательно open drain?
Точно не погорит, например, через полгодика-годик работы, если без диода?
Может у кого-нибудь есть схема готовая, чтобы быстро попробовать слать в UART в half duplex? А подтягивающий к питанию резистор заменить на подтягивающий к земле — сразу будет видно, open drain или нет.
Комментарии (25)
RSS свернуть / развернуть