реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> UART в Xmega, Проблема с настройкой скорости
Nosaer
сообщение Jul 17 2015, 12:29
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Здравствуйте)
Набросал не большой код:
UART настраивал на скорость в 9600 , 8 бит данных, 1 стоп бит и без бита парритета. Плюс отключен параметр удвоения скорости.

CODE
#define F_CPU 12000000UL
#define __DELAY_BACKWARD_COMPATIBLE__

#include <stdlib.h>
#include <avr/io.h>
#include <stdio.h>
#include <stddef.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

//Переменные
volatile char buf[26]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
volatile char dat[26]={0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};
unsigned char i,cnt,y;

// Функция включения USART_D1, cкорость 9600( а надо 250000) bod
void StartUsartD1()
{
USARTD1_BAUDCTRLB = 0;
USARTD1_BAUDCTRLA = 0x4D;
USARTD1_CTRLA = 0; //Отключение прерываний
USARTD1_CTRLC = USART_CHSIZE_8BIT_gc; //8 data bits, no parity and 1 stop bit
USARTD1_CTRLB = USART_TXEN_bm | USART_RXEN_bm; //Включение приема передатчика
PORTD_OUTSET = PIN7_bm; //Настраиваем выводы PC6 и PC7
PORTD_DIRSET = PIN7_bm;
PORTD_OUTCLR = PIN6_bm;
PORTD_DIRCLR = PIN6_bm;
}

// Функция получения данных USART_D1.
char getChar1(void)
{
char buffer1;
while (1)
{
while( !(USARTD1_STATUS & USART_RXCIF_bm) );
buffer1=USARTD1_DATA;
//if ((USARTD1_STATUS & (USART_BUFOVF_bm))==0)
if ((USARTD1_STATUS & (USART_FERR_bm | USART_PERR_bm | USART_BUFOVF_bm))==0)
return buffer1;
};
}

// Фунуция передачи данных USART_D1
void sendChar1(char d1)
{
while( !(USARTD1_STATUS & USART_DREIF_bm) );
USARTD1_DATA = d1;
}


// Функция инициализации
int main(void)
{
// Настройка работы от внешнего кварца в 12МГц
cli();
OSC.XOSCCTRL = 0x8B;

OSC.CTRL = 0x08;
while((OSC.STATUS & 0x08) == 0);

//PORTD.OUTSET =0x04;
PORTD.DIR = 0x04;

//Активация USART
StartUsartD1();

while (1)
{
cnt = getChar1();
if (cnt ==0x55) {
for (i=0;i<12;i++) sendChar1(buf[i]);

}
else {
for (i=0;i<12;i++) sendChar1(dat[i]); }
};
}

Скомпилировал, прошил, запускаю терминал
По моей задумке если я отправляю 0x55(символ юникода получается U) то мне шлется массив с 0xFF, если что нить другое то 0x55.
В итоге две проблемы:
1) ответ идет в виде массива 0x0E, в теории говорит что скорость настроена не правильно. Но вроде перепроверил все.


BSEL = 12000000/(2^0 * 16 * 9600) = 78.125 -1 = 77 (0x4D)
2) Как только прошил схему, без отправки контроллеру чего либо, он мне уже присылает в ответ 2 массива.

Помогите пожалуйста разобраться crying.gif=(

Сообщение отредактировал Nosaer - Jul 17 2015, 12:30
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Jul 17 2015, 16:19
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Куски из моего кода с инициализацией:

Код
    PORTE.DIRSET = PIN3_bm; // PE3 (TXD0) as output
    PORTE.DIRCLR = PIN2_bm; // PE2 (RXD0) as input
    PORTE_PIN2CTRL = (PORTE_PIN2CTRL & ~ PORT_OPC_gm) | PORT_OPC_PULLUP_gc;                            // pin is pulled high

    USARTE0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
    USARTE0.CTRLB = USART_RXEN_bm | USART_TXEN_bm;



    // Использование автоматического расчёта предделителя
    unsigned value;
    const uint_fast8_t prei = calcdivider(calcdivround(baudrate), ATXMEGA_UBR_WIDTH, ATXMEGA_UBR_TAPS, & value, 1);
    if (prei == 0)
        USARTE0.CTRLB |= USART_CLK2X_bm;
    else
        USARTE0.CTRLB &= ~USART_CLK2X_bm;
    // todo: проверить требование к порядку обращения к портам
    USARTE0.BAUDCTRLA = (value & 0xff);    /* Значение получено уже уменьшенное на 1 */
    USARTE0.BAUDCTRLB = (ATXMEGA_UBR_BSEL << 4) | ((value >> 8) & 0x0f);



Делители расчитаете и в ручную, ту просто что-то неочевидное при записи BAUDCTL A/B учитывать пришлось.

Полный код тут: https://188.134.5.254/browser/hfreceiver/trunk/hardware.c
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jul 17 2015, 17:00
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Genadi Zawidowski при разборе вашего "неочевидного" я вообще закипел)
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Jul 17 2015, 22:27
Сообщение #4


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Я не проверил работоспособность кода при ином порядке записи младшей/старшей половины делителя.
С чего "кипеть"? Попробуйте вашу инициализацию сделать аналогично.
Go to the top of the page
 
+Quote Post
smalcom
сообщение Jul 22 2015, 04:51
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718



1. Вы неправильно считаете.
2. Для работы с УАПП используют специальные кварцы: 7.3728, 11.0592, 14.7456 и подобные. Тогда при делении на целое число вы получите правильную скорость.
Приведу пример, чтобы было видно, что там всё просто считать

Код
    void SetBaudrate(uint32_t pBaudrate) const
    {
        if(pBaudrate != 0)
        {
            //attention: value of BSEL always is 0
            uint16_t ubrr;

            ubrr = F_PER / (16 * pBaudrate) - 1;

            mRegisterBase->CTRLB |= (1 << USART_RXEN_bp) | (1 << USART_TXEN_bp);
            mRegisterBase->BAUDCTRLA = (uint8_t)ubrr;
            mRegisterBase->BAUDCTRLB = ~USART_BSCALE_gm & (ubrr >> 8);
        }
        else
        {
            mRegisterBase->CTRLB &= ~((1 << USART_RXEN_bp) | (1 << USART_TXEN_bp));
        }
    }

, где F_PER - тактовая частота периферии. В моём случае это было: 7.3728 МГц(кварц) * 4(умножитель PLL)
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jul 27 2015, 11:13
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Почему не правильно то. Все как у Вас:
Цитата
ubrr = F_PER / (16 * pBaudrate) - 1;

12000000 / (16*9600) -1
Получаю 0x4D.


После недельных изысканий решил вновь обратиться за помощью.
Программу переделал, нашел несколько ошибок, реализовал передачу данных по прерыванию.
Алгоритм работы в следующем, я шлю что угодно, мне приходит 0x55. Если я шлю символ юникода "U"(он же 0x55), то в ответ должно прийти 0x77.

Проблемы собственно такие:
1) На настроенную скорость в 9600 шлется полнейший мусор. Если ставлю в терминале скорость от 9500 bod и ниже, то ответ начинает приходить более реальный в виде массива 0x55. Но если если я начинаю слать "U", то в ответ жду массив 0x77. А он приходит 1 раз из 5-10, в остальных 4-9 случаях приходит зачем то массив 0x55.
2) Отвечает контроллер не на каждую мою посылку. То есть раз 5 щелкнешь отправить, а ответ придет только один раз.

Вот собственно последняя версия программы:
CODE
#define F_CPU 12000000UL

#include <stdlib.h>
#include <avr/io.h>
#include <stdio.h>
#include <stddef.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

volatile char buf[5]={0x77,0x77,0x77,0x77,0x77};
volatile char dat[5]={0x55,0x55,0x55,0x55,0x55};
unsigned char i,cnt,y;

void StartUsartD1()
{
USARTD1_CTRLC= USART_PMODE1_bm | USART_CHSIZE0_bm | USART_CHSIZE1_bm;
USARTD1_BAUDCTRLB = 0;
USARTD1_BAUDCTRLA = 0x4D; //47 для 11,052 4D для 12
USARTD1_CTRLB = USART_TXEN_bm | USART_RXEN_bm;

USARTD1_CTRLA=USART_RXCINTLVL0_bm;

PORTD_OUTSET = PIN7_bm;
PORTD_DIRSET = PIN7_bm;
PORTD_OUTCLR = PIN6_bm;
PORTD_DIRCLR = PIN6_bm;
}

char getChar1(void)
{
while(1){
char buffer1;
buffer1=USARTD1_DATA;
//if ((USARTD1_STATUS & (USART_FERR_bm | USART_PERR_bm | USART_BUFOVF_bm))==0)
return buffer1;
}
}

void sendChar1(char d1)
{
while( !(USARTD1_STATUS & USART_DREIF_bm) );
USARTD1_DATA = d1;
}

ISR(USARTD1_RXC_vect)
{
cnt = getChar1();
}

int main(void)
{
// Clock Source Select
OSC.XOSCCTRL = 0x8B; // выбор внешнего генератора с временем запуска 16 тыс. CLK и частотой 8-12 МГц
OSC.CTRL = 0x08; // разрешение работы внешнего генератора
while((OSC.STATUS & 0x08) == 0); // ожидание появления в регистре статуса бита включения синхронизации от внешнего генератора
OSC_PLLCTRL = 0xC1; // настройка блока PLL на синхронизацию от внешнего источника и 1-х кратоное умножение
OSC_CTRL = OSC_CTRL | 0x10; // разрешение работы блока PLL
while((OSC_STATUS & 0x10) == 0 ) ; // ожидание появления в регистре статуса бита включения блока PLL
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_XOSC_gc;
OSC_CTRL = OSC_CTRL & 0xFE; // отключение системной синхронизации от внутреннего RC-генератора частотой 2 МГц

// Config Port
PORTD.DIR = 0x04;

StartUsartD1();

sei();
PMIC_CTRL = 1;

while (1)
{
PORTD.OUTSET =0x04; // Led
asm("NOP");
if (cnt != 0) {
if (cnt == 0x55) for (i=0;i<5;i++) sendChar1(buf[i]);
else for (i=0;i<5;i++) sendChar1(dat[i]); }
cnt = 0;

}
}


Уже и методом перебора прошелся по всем скоростям, пытаясь найти куда она уплыла из за какой нить погрешности.
И кварц на 11.0592 вместо 12Мгц ставил, как советовал выше smalcom, и на другие скорости перенастраивал. Поведение одно и то же.

Сообщение отредактировал Nosaer - Jul 27 2015, 11:17
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jul 27 2015, 13:29
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Подправил программу так, чтоб присылала мне то, что я отправил.
В итоге почему то когда отправляю U, вместо 55, приходит 55 FF. При отправке других символов такой проблемы нет.
Соответсвенно заменив U на другой символ проблема частично отпала.
Но погрешность по скорости все еще имеет место быть. т.е. при пересылке символов по одному, так называемое "эхо". Ошибок на скорости в 9600 нет, но при отправке массива, уже идет полный муссор
Go to the top of the page
 
+Quote Post
smalcom
сообщение Jul 27 2015, 17:20
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718



а покажите кусок схемы с МК и преобразователем в 232-й
Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jul 27 2015, 18:34
Сообщение #9


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



FT232 стоит на плате Pinboard II. К ней я тупо двумя проводками и цеплюсь.
Xmega ж с 2 двумя конденсаторами в обвязке кварца и и кренкой на 3,3 В стоит на обычной монтажке. Плюс несколько конденсаторов по питанию. Там ничего серьезного.
Единственное что питание у Pinboard идет с USB компьютера, а на отладочную плату с контроллером с отдельного БП.
Go to the top of the page
 
+Quote Post
smalcom
сообщение Jul 28 2015, 04:48
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718



> К ней я тупо двумя проводками и цеплюсь.
ну и общий, да?

и на всякий случай попробуйте ожидать конца передачи. т.е.
Код
void sendChar1(char d1)
{
    while( !(USARTD1_STATUS & USART_DREIF_bm) );
    USARTD1_DATA = d1;
}

дополнить до
Код
void sendChar1(char d1)
{
    while( !(USARTD1_STATUS & USART_DREIF_bm) );
    USARTD1_DATA = d1;
    while( !(USARTD1_STATUS & USART_TXCIF_bm) );
}


Go to the top of the page
 
+Quote Post
Nosaer
сообщение Jul 28 2015, 13:27
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 85
Регистрация: 6-02-15
Пользователь №: 84 967



Ожидание конца передачи не помогло)
Решил проблему иначе. Этот кусок кода сунул в обработку прерывания по приему данных с UART. Буфер с данными по команде cnt = 0; опустошался быстрее, чем подпрограмма успевала его обработать. Поэтому и были пропущенные команды.

Код
  if (cnt != 0) {
  if (cnt == 0x55) for (i=0;i<5;i++) sendChar1(buf[i]);
         else for (i=0;i<5;i++) sendChar1(dat[i]); }
  cnt = 0;


Скорость под 9600 подобрал методом подгона.

Сообщение отредактировал Nosaer - Jul 28 2015, 13:28
Go to the top of the page
 
+Quote Post
ESN
сообщение Aug 7 2015, 10:05
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 4-10-10
Из: г.Псков
Пользователь №: 59 908



При F_PER =12 000 000 Гц и F_Baud=9600 bit/s чтобы минимизировать ошибки обмена следует положить регистр BSCALE=-3 , тогда BSEL станет равным $0269 - целым числом, что делает обмен стопроцентным. Вообще, следует сделать расчеты для всех значений BSCALE (от -7 до 7) и выбрать тот вариант, где BSEL имеет минимальную дробную часть. При записи в регистры управления вместо -3 следует писать $0d. Т.о получаем: USART_BAUDCTRLA=$69 и USART_BAUDCTRLB=$d2 - параметры задающие скорость.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 11:19
Рейтинг@Mail.ru


Страница сгенерированна за 0.01471 секунд с 7
ELECTRONIX ©2004-2016