Здравствуйте!
Я использую USB как отладочный интерфейс на плате с ATXmega32a4u. В основном цикле программы я опрашиваю АЦП и подсчитываю количество выборок. Раз в 20 мс срабатывает внешнее прерывание на одном из портов общего назначения. По прерыванию я провожу вычисления, а результаты вычислений и количество отсчётов я помещаю в строку, которую затем буду передавать по USB. Проблема: если отключить модуль USB совсем, я успеваю получить около 900 отсчётов, как и было задумано, но с USB в большинстве случаев 0, иногда около 450. Такие значения оказываются в строке, да и отладка светодиодом показывает то же самое. В прерывании включаю светодиод, если отсчётов > 800, выключаю, если меньше. Если USB-кабель подключен - не горит, отключаю - горит.
Функция main:
CODE
box#include <asf.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "main.h"
volatile uint64_t g_squared_sum;
volatile uint16_t g_samples;
volatile uint8_t g_signal_phase;
volatile uint8_t g_duty_cycle = 50;
volatile char g_usb_string[81];
volatile bool g_usb_timeout_is_counted = false;
ISR(PORTD_INT0_vect);
ISR(BADISR_vect);
ISR(TCC0_OVF_vect);
ISR(TCC0_CCA_vect);
ISR(TCC0_CCB_vect);
ISR(TCC1_OVF_vect);
void vbus_event(bool vbus);
uint32_t get_RMS(void);
uint32_t average(uint32_t new_RMS);
int main (void)
{
int32_t adc_result;
irq_initialize_vectors(); // enable all irq priorities
sei();
sysclk_init(); // turns off all peripheral. It reduces noise to ADC
sysclk_enable_module(SYSCLK_PORT_A, SYSCLK_ADC); // turn on ADC on port A
sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); // turn on TC0 clock
sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC1); // turn on TC1 clock
#ifdef DEBUG2
stdio_usb_init(); // enables and attaches USB, readdress std streams to USB
#endif
board_init(); // LEDs,buttons, ADC, TC0 settings
while(1)
{
if(ADCA.CH0.INTFLAGS)
{
adc_result = (int32_t)ADCA.CH0.RES - ADC_OFFSET - BOARD_OFFSET;
cli(); // need cli and sei to avoid executing irq
g_samples += 1; // between changing g_samples and g_squared_sum
g_squared_sum += (uint64_t) (adc_result * adc_result);
sei(); // now irq enabled
ADCA.CH0.INTFLAGS = 1; // clean flag
}
}
}
Вот прерывание:
Код
ISR(PORTD_INT0_vect)
{
average(get_RMS());
tcc0_restart();
PORTB.OUTCLR = PIN3_bm;
g_signal_phase = 0;
}
Формирование строки для USB происходит в функции get_RMS()
CODE
uint32_t get_RMS(void)
{ // count RMS based on global variables g_squared_sum, g_samples,
// that are accumulated in a main loop
uint32_t result = 0;
if(g_samples)
result = (uint32_t) sqrt(g_squared_sum/g_samples);// to avoid dividing by zero
#ifdef DEBUG2
sprintf(g_usb_string, "result= %lu, sq_sum = 0x%lX%lX, samples = %u\r\n",
result, (uint32_t)(g_squared_sum>>32), (uint32_t)g_squared_sum, g_samples);
#endif
g_samples = g_squared_sum = 0; // reset accumulated sum and samples counter
return result;
}
Для работы с USB использую библиотеку ASF. Устройство нормально подключается, опознаётся. Чтобы получить строку, я отправляю через Putty символ, на что мне оно отвечает заранее подготовленной строкой из функции обратного вызова от драйвера интерфейса по получении данных в USB.
Код
void my_callback_rx_notify(uint8_t port)
{
char c;
stdio_usb_getchar(0, &c);
stdio_usb_write(g_usb_string, strlen(g_usb_string));
}
Может ли USB так влиять? Опять же отладка светодиодами показала, что большую часть времени процессор проводит всё же в цикле main, а не в прерываниях USB. Может, я как-то не так передаю значение счётчика? Объявлен глобальной переменной со спецификатором volatile.
Помогите, пожалуйста!
Сообщение отредактировал IgorKossak - Jun 6 2014, 15:23
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!