Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с usart
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
THI
Здравствуйте, уважаемые форумчане!

Существует плата с неким функционалом для работы с пк через usb. Используемый мк был msp430, а теперь решили перейти на stm. И при первоначальных тестах у меня возникли 2 проблемы. Первая проблема - это отправка данных с платы через уарт на пк. На прием все работало хорошо. Открыл список регистров, выяснилось что в регистр USART1->DR не записываются данные. Решил проверить, запишется ли значение в usart2->dr. Добавил код настройки 2го уарта, запустил... и обнаружил, что в оба уарта теперь вообще ничего не записывается, ни в один регистр. Попытался убрать код, проблема осталась. Собственно, это 2 проблема. Используемый код
CODE
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
int i;

char* trans_dist;
int trans_n, trans_cur;
char flag_1 = 0;
char text_1[]={'h','e','l','l','o'};

void Transmit_data(char* source, int n)
{
int i=0;
for(;i<n;i++)
{
//volatile char temp;
USART1->SR &= ~USART_SR_TC;
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = *source;
//temp = USART1->DR;
++source;
if (i==(n-1))
flag_1 = 0;
}
}



int main(void)
{
RCC->CR|=RCC_CR_HSION;
while (!(RCC->CR & RCC_CR_HSIRDY));
RCC->CFGR &=~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_HSI;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
GPIOA->CRL |= GPIO_CRL_CNF1_0 | GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2_1 | GPIO_CRL_CNF4_1 | GPIO_CRL_MODE4_1 |
GPIO_CRL_CNF5_0 | GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0;
GPIOA->CRL &= ~(GPIO_CRL_CNF2_0 | GPIO_CRL_CNF4_0);
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_1 | GPIO_CRH_CNF10_0 | GPIO_CRH_CNF12_1 | GPIO_CRH_MODE12_1;
GPIOA->CRH &= ~(GPIO_CRH_CNF9_0 | GPIO_CRH_CNF12_0);
GPIOB->CRL |= GPIO_CRL_MODE0_1 | GPIO_CRL_MODE1_1 | GPIO_CRL_MODE2_1;
GPIOB->CRH |= GPIO_CRH_MODE10_1 | GPIO_CRH_MODE12_1 | GPIO_CRH_CNF13_0;
GPIOC->CRH |= GPIO_CRH_CNF13_0;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
USART1->BRR = (8000000+19200/2)/19200;
USART1->CR1 |= USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
USART1->CR1 |= USART_CR1_UE;
//USART2->BRR = (8000000+19200/2)/19200;
//USART2->CR1 |= USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
//USART2->CR1 |= USART_CR1_UE;
NVIC_EnableIRQ(USART1_IRQn);

while(1)
{
if (flag_1)
Transmit_data(text_1, 5);
//USART1->DR |= 49;
}
}
void USART1_IRQHandler(void)
{
//char t;
if(USART1->SR & USART_SR_RXNE)
{
flag_1 = 1;
USART1->SR &= ~USART_SR_RXNE;
//t = USART1->DR;
}
if(USART1->SR & USART_SR_TXE)
{
//USART1->SR &= ~USART_SR_TXE;
}
}

PA2 и PA3 - выход и вход для usart2, PA9 и PA10 - выход и вход для usart1
Среда: CooCox CoIDE 1.6.2, мк: stm32f100c4
Интересно ваше мнение по поводу обеих проблем.
kan35
У вас вроде бы GPIO настроены не верно.
Все альтернативные порты USART должны быть настроены как alternative push pull (и RX и TX линии).
И в функции передатчика вы делаете сброс битов не рекомендованным способом, из чего вывод - лучше используйте библиотеки ST, особенно в настройке GPIO это актуально - код нечитаем, оттого и ошибки. Тем более, библиотеки у вас подключены уже как видно из команд подачи тактирования на USART.
maksimp
Цитата(THI @ Mar 4 2013, 16:57) *
в регистр USART1->DR не записываются данные.

Почему вы решили что не записываются? Записали, потом считали и сравнили с тем что записывали?
Но USARTx->DR - это на самом деле 2 независимых регистра. При записи это регистр данных передатчика, при чтении - регистр данных приёмника. В общем случае прочтённое из этого регистра не равно тому что только что в него было записано.
Отмечу что отладчик не имеет магического способа доступа к регистрам, он их пишет и читает так же как и программа процессорного ядра. Просмотр USARTx->DR в отладчике приводит к потере принятых данных, так как при этом флаг наличия данных сбрасывается.
Цитата(kan35 @ Mar 4 2013, 20:12) *
Все альтернативные порты USART должны быть настроены как alternative push pull (и RX и TX линии).

Нет, RX должна быть настроена как вход или вход с подтяжкой.
TX - да, alternative push pull (но при необходимости можно и alternative open drain).
THI
kan35, maksimp спасибо что откликнулись
Цитата
И в функции передатчика вы делаете сброс битов не рекомендованным способом, из чего вывод - лучше используйте библиотеки ST, особенно в настройке GPIO это актуально - код нечитаем, оттого и ошибки. Тем более, библиотеки у вас подключены уже как видно из команд подачи тактирования на USART.

Настройка GPIO сделана вручную из-за того, что есть некоторые выводы должны быть настроены как "push-pull", другие как "input floating". Недавно сел за CooCox, необходимой функции настройки не нашел, а GPIO_Init не подходит.
По поводу сброса битов - это да, спасибо.
Цитата
Но USARTx->DR - это на самом деле 2 независимых регистра. При записи это регистр данных передатчика, при чтении - регистр данных приёмника. В общем случае прочтённое из этого регистра не равно тому что только что в него было записано.
Отмечу что отладчик не имеет магического способа доступа к регистрам, он их пишет и читает так же как и программа процессорного ядра. Просмотр USARTx->DR в отладчике приводит к потере принятых данных, так как при этом флаг наличия данных сбрасывается.

По поводу регистра DR - каюсь, видимо плохо читал документацию, буду перечитывать, может и ещё что найду. А вот по поводу отладчика сам бы нескоро догадался, спасибо.
И все-таки, чем могла быть вызвана вторая проблема и можно ли ее как то исправить?
Elcarnado
Здравствуйте! Я тоже недавно начал разбираться с STM32, так что подсказать мало чем смогу, но мою настройку рабочего USART с радостью предоставлю, может поможет...
CODE
#define USART_DBG_GPIO GPIOA
#define USART_DBG_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART_DBG_RxPin GPIO_Pin_10
#define USART_DBG_TxPin GPIO_Pin_9

void USART_Configure(unsigned int baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

/* Enable GPIO and USART_DBG clock */
RCC_APB2PeriphClockCmd(USART_DBG_GPIO_CLK | USART_DBG_CLK | RCC_APB2Periph_AFIO, ENABLE);

/* Configure USART_DBG Tx */
GPIO_InitStructure.GPIO_Pin = USART_DBG_TxPin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // Скорость обновления пина
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // Режим - альтернативный Push-Pull
GPIO_Init(USART_DBG_GPIO, &GPIO_InitStructure);

/* Configure USART_DBG Rx */
GPIO_InitStructure.GPIO_Pin = USART_DBG_RxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // Режим - Открытый вход
GPIO_Init(USART_DBG_GPIO, &GPIO_InitStructure);

/* Caonfigure USART parameters*/
USART_InitStructure.USART_BaudRate = baudrate;
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_Rx | USART_Mode_Tx;
USART_Init(USART_DBG, &USART_InitStructure);
USART_Cmd(USART_DBG, ENABLE);
USART_SendData(USART_DBG,'A'); // Отправляем символ А в порт
}


Еще один # define забыл ))

Необходимо добавить

#define USART_DBG_CLK RCC_APB2Periph_USART1
THI
Elcarnado
спасибо за пример, но я уже пробовал настраивать уарт через USART_Init, не помогло.
Ещё вопрос, по конкретнее, существует ли биты блокировки настройки USART'а? Я правда таких не нашел, но думаю стоит спросить.
Сергей Борщ
QUOTE (THI @ Mar 7 2013, 11:52) *
существует ли биты блокировки настройки USART'а?
Это биты, отключающие его тактирование. Без тактирования ни один из регистров писаться не будет, читаться будут нули. Других нету.
maksimp
Цитата(THI @ Mar 7 2013, 12:52) *
существует ли биты блокировки настройки USART'а?

Ещё есть регистры сброса периферии RCC_APB1RSTR и RCC_APB2RSTR (п. 7.3.4, 7.3.5 в reference manual). Если выставить в них бит в то работа соответствующего модуля блокируется.

Цитата(THI @ Mar 4 2013, 16:57) *
Добавил код настройки 2го уарта, запустил... и обнаружил, что в оба уарта теперь вообще ничего не записывается, ни в один регистр.

Вы разрешили прерывания от USART2, но обработчик прерывания не написали.
Прерывание происходит, флаг прерывания не сбрасывается, прерывание снова тут же проиходит и т.д. Программа перестаёт выполняться.
THI
Всем спасибо, кто ответил, извиняюсь, что так долго не писал.
Вобщем 2 проблема решилась загрузкой другой прошивки, написанной, собственно, по примеру Elcarnado. Потом была залита предыдущая прошивка, настройка уарта работает.
В чем была причина так и не разобрались. Второй уарт также был проверен (косвенно), похоже что ситуация такая же, как и с первым.
maksimp
Как я писал, настройка 2 уарта делается, по крайней мере, причина была не в прерываниях.
Rimsky
Здравствуйте друзья.
Инициализировал USART1 (МК STM32F100C4T6) при помощи стандартной библиотеки STDLib
CODE
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStructure;


#if !defined REMAP_USART1
// Включаем тактирование порта А и USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// Настраиваем ногу TxD (PA9) как выход push-pull c альтернативной функцией
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);

#else
/** USART1 GPIO Configuration
PB6 ------> USART1_TX
PB7 ------> USART1_RX
*/

/*Enable or disable APB2 peripheral clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);

/*Configure GPIO pin */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);

/*Configure GPIO pin */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStruct);

/*Configure peripheral I/O remapping */
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
#endif
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = 9600*2;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);

/* Enable the USART1 */
USART_Cmd(USART1, ENABLE);

/* Enable USART1 Receive and send interrupts */
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART1, USART_IT_TC, ENABLE);

NVIC_EnableIRQ(USART1_IRQn); // Разрешение прерывания USART1


Но вот символьная скорость вместо 9600 бод как заказывал, в 2 раза меньше. В чем может быть причина?
Rimsky
Открыл исходник (stm32f10x_usart.c) там в функции USART_Init(...) обнаружен такие строчки :
Код
/* USART OverSampling-8 Mask */
#define CR1_OVER8_Set             ((u16)0x8000)  /* USART OVER8 mode Enable Mask */
#define CR1_OVER8_Reset           ((u16)0x7FFF)  /* USART OVER8 mode Disable Mask */


if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
  {
    /* Integer part computing in case Oversampling mode is 8 Samples */
    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));    
  }
  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
  {
    /* Integer part computing in case Oversampling mode is 16 Samples */
    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));    
  }


Кто объяснит, где в регистре USART_CR1 бит (CR1_OVER8) ???


Разобрался, для корректной работы с SPL нужно определить HSE_VALUE (частоту внешнего кварца), если это значение не определено, то из файла STM32f10x.h подставляется дефолтное:
Код
#if !defined  HSE_VALUE
#ifdef STM32F10X_CL  
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
adnega
Цитата(Rimsky @ Mar 8 2014, 15:09) *
Кто объяснит, где в регистре USART_CR1 бит (CR1_OVER8) ???

Reference manual только и объяснит. Читали?
Rimsky
Цитата(adnega @ Mar 8 2014, 20:51) *
Reference manual только и объяснит. Читали?


Читал, только в МК STM32F100C4T6 такого бита в регистре USART_CR1 нет.

В прочем с этим я разобрался. sm.gif
adnega
Цитата(Rimsky @ Mar 9 2014, 03:59) *
В прочем с этим я разобрался. sm.gif

И какое же правильный ответ?
Определить HSE_VALUE?

1. По поводу OVER8.
В других МК он есть на месте 15 бита. В F100 он жестко обнулен, что соответствует 16 выборкам.
Позицию бита можно было узнать из RM на дригие МК или по маске из библиотеки.
В RM на ваш МК можно найти фразу, что начиная с 14 бита по 31 в регистре CR1 железные нули.

2. По поводу HSE_VALUE.
Я не фанат стандартной библиотеки, но когда только она появилась и долгое время после имел
некоторые проблемы как раз с HSE_VALUE. Дело в том, что для внешнего кварца у STM приняты
стандартные значения в 8 или 25 МГц, а я (уж так сложилось исторически) применяю кварцы на
12 МГц. Делители библиотека рассчитывает исходя из заданного HSE_VALUE и стандартного для
указанного семейства кварца. Я правил код библиотеки под себы, но это великое зло.
Интересно, это до сих пор так? (вопрос разобравшемуся человеку sm.gif)
Rimsky


Цитата(adnega @ Mar 9 2014, 14:36) *
1. По поводу OVER8.
В других МК он есть на месте 15 бита. В F100 он жестко обнулен, что соответствует 16 выборкам.
Позицию бита можно было узнать из RM на дригие МК или по маске из библиотеки.
В RM на ваш МК можно найти фразу, что начиная с 14 бита по 31 в регистре CR1 железные нули.

В общем так я и поступил. Смутило то, что SPL взято с stm32gui_lib в котором идет явная привязка к МК STM32F10x....

Цитата(adnega @ Mar 9 2014, 14:36) *
2. По поводу HSE_VALUE.
Я не фанат стандартной библиотеки, но когда только она появилась и долгое время после имел
некоторые проблемы как раз с HSE_VALUE. Дело в том, что для внешнего кварца у STM приняты
стандартные значения в 8 или 25 МГц, а я (уж так сложилось исторически) применяю кварцы на
12 МГц. Делители библиотека рассчитывает исходя из заданного HSE_VALUE и стандартного для
указанного семейства кварца. Я правил код библиотеки под себы, но это великое зло.
Интересно, это до сих пор так? (вопрос разобравшемуся человеку sm.gif)

В расчете baud rate для USARTA есть вызов процедуры RCC_GetClocksFreq(&RCC_ClocksStatus); Которая инициализирует значения структуры RCC_ClocksStatus элементы которой участвуют в расчете. В этой процедуре и фигурирует определение HSE_VALUE. Если оно не соответствует Вашему кварцу, то и расчет будет не верным. У меня кварц на 4096000, что отличается от дефолтного в 2 раза, вот тут то и были грабли.
adnega
Цитата(Rimsky @ Mar 9 2014, 12:06) *
Если оно не соответствует Вашему кварцу, то и расчет будет не верным. У меня кварц на 4096000, что отличается от дефолтного в 2 раза, вот тут то и были грабли.

Т.е. Вы задали HSE_VALUE = 36864000 ?
Фиксированный умножитель на 9 Вас устраивает?
В моем случае 12МГц умноженые на 9 давали не работоспособные 108 МГц и правка HSE_VALUE = 108000000 не спасала((
Rimsky
Цитата(adnega @ Mar 9 2014, 20:00) *
Т.е. Вы задали HSE_VALUE = 36864000 ?
Фиксированный умножитель на 9 Вас устраивает?
В моем случае 12МГц умноженые на 9 давали не работоспособные 108 МГц и правка HSE_VALUE = 108000000 не спасала((


Нет, HSE_VALUE я установил 4096000

Код
#if !defined  HSE_VALUE
#ifdef STM32F10X_CL  
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
  #define HSE_VALUE    ((uint32_t)4096000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
adnega
Цитата(Rimsky @ Mar 10 2014, 03:52) *
Нет, HSE_VALUE я установил 4096000

Код
#if !defined  HSE_VALUE
#ifdef STM32F10X_CL  
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
  #define HSE_VALUE    ((uint32_t)4096000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */

Это частота внешнего кварца, а не частота с PLL. Точно.
Т.е. Вы поправили библиотечный файл?
Rimsky
Цитата(adnega @ Mar 10 2014, 13:27) *
Это частота внешнего кварца, а не частота с PLL. Точно.
Т.е. Вы поправили библиотечный файл?


Да это частота внешнего кварца. Библиотечный файл можно и не править, достаточно объявить это определение, например так:
Код
#ifndef __GLOBALS_H
#define __GLOBALS_H

#define HSE_VALUE ((uint32_t)4096000)

#include "stm32f10x.h"
#include "stm32f10x_conf.h"
adnega
Цитата(Rimsky @ Mar 10 2014, 09:50) *
Да это частота внешнего кварца. Библиотечный файл можно и не править, достаточно объявить это определение, например так:
Код
#ifndef __GLOBALS_H
#define __GLOBALS_H

#define HSE_VALUE ((uint32_t)4096000)

#include "stm32f10x.h"
#include "stm32f10x_conf.h"

Объявить в каком файле?
В stm32f10x_conf.h (любом .h-файле, вызаваемом из stm32f10x_conf.h) или в совершенно произвольном месте?
А может в ключах компилятора?

А если у меня частота кварца 12МГц, то какая будет частота PLL? А если мне нужна другая частота PLL?

Спрошу по-другому: можно ли библиотеке указать частоту кварца 12МГц и частоту PLL 72МГц? И чтоб при этом все делители для UART рассчитывались правильно.
Golikov A.
можно прочитать главу мануала за 10 минут, а потом за 8 минут настроить правильно делители PLL и забить на все эти библиотеки. Библиотека на то и библиотека, чтобы гнать какой-то стандарт. В случае частоты, чем больше тем лучше, вот и выводят проц на максимум... А если пошли уже все фигли мигли, то ручками, ручками
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.