:::: MENU ::::

STM32F429 — USART Multiprocessor, 9 bit mode

Обычно USART используют для подключения устройств point to point. А для подключения нескольких устройств на одну шину данных используют — SPI или I2C. Но USART, в некоторых его реализациях, тоже может обеспечить работу работу более двух устройств на одной шине.

Обычно для этого используют 9-битный протокол. В 9-битном протоколе на шину может передаваться адрес или данные. Адрес принимают все контроллеры на шине и сравнивают со своим адресом. Данные принимает только один контроллер, тот у которого адрес (последний посланный на шину адрес) совпал. Остальные контроллеры не принимают данные, пока на шине не появится новый адрес.

«Не прием» данных, по шине при несовпадении адреса может быть реализован как аппаратно — прерывания на прием не будут поступать, так и программно — тогда вам надо самим в обработчике прерываний проверять адрес и отбрасывать данные если они пришли не вам.

9 битный этот протокол называется, потому что обычно 9-й бит указывает — пришел адрес или данные (9 бит установлен — адрес, не установлен — данные). Но, в принципе, данный протокол может быть реализован и с 8 битами, но только информационных у вас окажутся только 7 бит, а 8 бит будет отвечать за переключение адрес/данные.

USART STM32F429 имеет Multiprocessor mode — аппаратный 9-bit Multiprocessor протокол. Но в нем для адресациии используются только младшие 4 бита. Что довольно странно — т.к. обычно для адресации используются все оставшиеся 8 бит, а значит данный режим будет не совместим с другими аналогичными 9-bit протоколами контроллеров других производителей. Но кроме того, STM32F429 может принимать все девять бит, как биты данных — а значит 9-битный протокол можно реализовать программно (с обработкой всех данных в обработчике прерывания и их отбрасыванием в случае неправильной адресации). Далее будет рассмотрены оба варианта.

Аппаратная реализация

USART в данном режиме нужно настроить как 9-bit mode и отключить проверку четности/нечетности, после для slave настроить адрес, включить выход из режима игнорирования данных по приходу адреса и отправить usart в mute mode в котором он будет игнорировать все данные до соответствующего адреса.

usart_9bit_mode

GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); 

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; 
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz; 
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);

GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);

USART_InitStruct.USART_BaudRate = 9600; 
USART_InitStruct.USART_WordLength =  USART_WordLength_9b; 
USART_InitStruct.USART_StopBits = USART_StopBits_1; 
USART_InitStruct.USART_Parity = USART_Parity_No; 
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
USART_Init(USART2, &USART_InitStruct);
USART_Cmd(USART2, ENABLE);

USART_SetAddress (USART2, 1); // set address usart
USART_WakeUpConfig (USART2, USART_WakeUp_AddressMark); // wakeup mode
USART_ReceiverWakeUpCmd (USART2, ENABLE); // usart is mute    

Для master настройки такие-же кроме последних 3 строчек кода (выше). Т.е. ему не нужны адрес, ему не нужно уходить в mute mode, поскольку master будет принимать ответы от всех других контроллеров на шине. Если master хочет отправить кому-то пакет данных, то перед отправлением пакета он должен послать на шину адрес устройства, которому он хочет послать пакет и при этом 9 бит в этой адресной посылке должен быть выставлен в 1:

adr_data = ADR | 0x0100;
USART_SendData(USART1, adr_data);

После отправления адреса, можно отправлять непосредственно сам пакет данных.

Простенький тестовый проект для данного режима приложен — см. в конце статьи(для IAR, STM32F429-Disco).

Программно-аппаратная реализация

Если необходимо использовать более 4 бит для адреса устройств — то можно сделать программно-аппаратную реализацию 9-битного режима. Программно — поскольку теперь всю проверку адреса/данных будем делать программно в прерываниях. Аппаратно — поскольку все же можно выставить 9-битный USART и принимать 9 бит данных, а не 8 (многие др. контроллеры такого не умеют — работают только с 8 битами).

Настройка USART для slave и master будет такая-же как у master из предыдущего примера:

GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); 

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; 
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz; 
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);

GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);

USART_InitStruct.USART_BaudRate = 9600; 
USART_InitStruct.USART_WordLength =  USART_WordLength_9b; 
USART_InitStruct.USART_StopBits = USART_StopBits_1; 
USART_InitStruct.USART_Parity = USART_Parity_No; 
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
USART_Init(USART2, &USART_InitStruct);
USART_Cmd(USART2, ENABLE);

В обработчике прерывания по приему Slave нужно реализовать такой код:

uint16_t input_data = 0;
uint8_t adr_data = 0;
uint8_t f_adr_input = 0;
static uint8_t f_adr_mode = 0;
uint8_t tmp;


input_data = USART_ReceiveData(USART2);

// адрес или данные
if( (input_data & 0x0F00) != 0)
    f_adr_input = 1;

// пришел адрес
if(f_adr_input == 1)
{
    // проверяем адрес 
    adr_data = input_data & 0x00FF;

    if(adr_data == MY_ADR)
    {
        // адрес совпал - далее данные мне
        f_adr_mode = 1;
    }
    else
    {
        // адрес совпал - данные не мне
        f_adr_mode = 0;
    }            
}
// пришли данные
else
{
    // если до этого адресация была нам
    // то данные нам
    // иначе данные отбрасываем - не нам
    if(f_adr_mode == 1)
    {
        buf_rec[i_buf_rec] = USART_ReceiveData(USART2);
        i_buf_rec++;
        if(i_buf_rec == S_BUF)
            i_buf_rec = 0;
    }
    else
    {
        tmp = USART_ReceiveData(USART2);                
    }
}

Думаю код понятен без объяснения — делаем тоже самое, что должен бы бы сделать USART в данном режиме аппаратно.

Простенький тестовый проект для данного режима приложен (для IAR, STM32F429-Disco).

EXAMPLE PRJ аппаратный 9-bit mode — stm32f429_start_9bit_hardware .

EXAMPLE PRJ программно-аппаратный 9-bit mode — stm32f429_start_9bit_software .