MSP430 не в состоянии справиться с двойной - PullRequest
0 голосов
/ 27 марта 2012

Я пытаюсь запрограммировать MSP430 с помощью простой программы «FIR filter», которая выглядит следующим образом:

#include "msp430x22x4.h"
#include "legacymsp430.h"

#define FILTER_LENGTH 4
#define TimerA_counter_value 12000                // 12000 counts/s -> 12000 counts ~ 1 Hz

int i;
double x[FILTER_LENGTH+1] = {0,0,0,0,0};
double y = 0;
double b[FILTER_LENGTH+1] = {0.0338,    0.2401,    0.4521,    0.2401,    0.0338};

signed char floor_and_convert(double y);

void setup(void)
{
WDTCTL = WDTPW + WDTHOLD;                       // Stop WDT
BCSCTL1 = CALBC1_8MHZ;                          // Set DCO
DCOCTL = CALDCO_8MHZ;

/* Setup Port 3 */
P3SEL |= BIT4 + BIT5;                           // P3.4,5 = USART0 TXD/RXD
P3DIR |= BIT4;                                  // P3.4 output direction

/* UART */
UCA0CTL1 = UCSSEL_2;                            // SMCLK
UCA0BR0 = 0x41;                                 // 9600 baud from 8Mhz
UCA0BR1 = 0x3;
UCA0MCTL = UCBRS_2;                       
UCA0CTL1 &= ~UCSWRST;                           // **Initialize USCI state machine**
IE2 |= UCA0RXIE;                                // Enable USCI_A0 RX interrupt

/* Setup TimerA */
BCSCTL3 |= LFXT1S_2;                            // LFXT1S_2: Mode 2 for LFXT1 = VLO 
                                                // VLO provides a typical frequency of 12kHz
TACCTL0 = CCIE;                                 // TACCR0 Capture/compare interrupt enable
TACCR0 = TimerA_counter_value;                  // Timer A Capture/Compare 0: -> 25 Hz
TACTL = TASSEL_1;                               // TASSEL_1: Timer A clock source select: 1 - ACLK 

TACTL |= MC_1;                                  // Start Timer_A in up mode  
__enable_interrupt();
}

void main(void)                                   // Beginning of program
{
setup();                                       // Call Function setup (see above)
_BIS_SR(LPM3_bits);                            // Enter LPM0
}


/* USCIA interrupt service routine */
                                                /*#pragma vector=USCIAB0RX_VECTOR;*/
                                                /*__interrupt void USCI0RX_ISR(void)*/
interrupt (USCIAB0RX_VECTOR) USCI0RX_ISR(void)
{  

TACTL |= MC_1;                                  // Start Timer_A in up mode

x[0] =  (double)((signed char)UCA0RXBUF);      // Read received sample and perform type casts
y = 0;
for(i = 0;i <= FILTER_LENGTH;i++)           // Run FIR filter for each received sample
{
    y += b[i]*x[i];
}       
for(i = FILTER_LENGTH-1;i >= 0;i--)         // Roll x array in order to hold old sample inputs
{
    x[i+1] = x[i];
}

while (!(IFG2&UCA0TXIFG));                      // Wait until USART0 TX buffer is ready?
UCA0TXBUF = (signed char) y;
TACTL |= TACLR;                                 // Clear TimerA (prevent interrupt during receive)
}

/* Timer A interrupt service routine */
                                                /*#pragma vector=TIMERA0_VECTOR;*/
                                                /*__interrupt void TimerA_ISR (void)*/
interrupt (TIMERA0_VECTOR) TimerA_ISR(void)
{
for(i = 0;i <= FILTER_LENGTH;i++)           // Clear x array if no data has arrived after 1 sec
{
    x[i] = 0;
}
TACTL &= ~MC_1;                                 // Stops TimerA
}

Программа взаимодействует с кодом MatLab, который отправляет 200 удваивается в MSP,для обработки в КИХ-фильтре.Моя проблема в том, что MSP не в состоянии справиться с двойниками.Я использую MSPGCC для компиляции кода.Когда я отправлю int в MSP, он ответит снова отправкой int.

Ответы [ 4 ]

2 голосов
/ 28 марта 2012

Ваша проблема в том, что данные отправляются в MSP.

Связь с MATLAB, согласно вашему коду, представляет собой последовательность из 4 двоичных байтовых значений, которые вы затем берете из последовательного порта и приводите его к двойному значению. Входящее значение будет иметь диапазон от -128 до +127.

Если ваши исходные данные имеют любой другой размер данных, то ваша программа будет повреждена. Если ваш источник данных предоставляет двоичные «двойные» данные, то каждое значение может иметь длину 4 или 8 байтов в зависимости от его внутреннего представления данных. Отправка одного из этих значений через последовательный порт будет интерпретироваться MSP как полный набор из 4 входных выборок, что приведет к абсолютному мусору для набора ответов.

Действительно большой вопрос: ПОЧЕМУ НА ЗЕМЛЕ ВЫ ЭТО ДЕЛАЕТЕ В ПЛАВУЩЕЙ ТОЧКЕ - на 16-разрядном целочисленном процессоре, который (во многих версиях) имеет аппаратное целочисленное умножение.

1 голос
/ 23 июля 2012

Как сказал Ян, вы берете 8-битное значение (UCA0RXBUF в любом случае имеет ширину всего 8 бит) и ожидаете получить из него 32-битное или 64-битное значение.

Для получения правильной выборкивам нужно будет прочитать UCA0RXBUF несколько раз, а затем конкатенировать каждое 8-битное значение в 32/64 бита, которые вы затем приведете к двойному.

Как и Ян, я бы также поставил под сомнение целесообразность выполнения математики с плавающей запятой вВстроенный микроконтроллер с низким энергопотреблением.Этот тип задачи гораздо лучше подходит для DSP.

По крайней мере, вы должны использовать математику с фиксированной точкой, см. wikipedia (даже в DSP вы использовали бы арифметику с фиксированной точкой).

0 голосов
/ 13 октября 2014

Также не рекомендуется, чтобы подпрограммы прерывания выполняли длинные подпрограммы обработки, поскольку это повлияет на задержку прерывания. Прибытие байтов с ПК может быть легко потеряно из-за переполнения буфера на последовательном порту.

Лучше всего создать буфер FIFO, содержащий разумное количество входных значений. Подпрограмма USCI заполняет FIFO, в то время как основная программа продолжает искать внутри него данные и обрабатывать их по мере их доступности.

Таким образом, во время обработки данных USCI может прерывать обработку новых поступающих байтов.

Когда FIFO пуст, вы можете перевести основной процесс в подходящий режим LPM для экономии энергии (и это функция best MSP430). Процедура USCI разбудит процессор, когда данные будут готовы (просто поместите атрибут WAKEUP в обработчик USCI, если вы используете MSPGCC).

В таком сценарии обязательно объявите volatile каждую переменную, которая используется совместно для подпрограмм прерывания и основного процесса.

0 голосов
/ 28 марта 2012

Хм.На самом деле код написан моим учителем, я просто пытаюсь заставить его работать на моем Mac, а не в AIR: -)

Код MATLAB выглядит так:

function FilterTest(comport)
Fs  =   100;            % Sampling Frequency
Ts  =   1/Fs;           % Sampling Periode
L = 200;                % Number of samples

N = 4;                  % Filter order
Fcut = 5;               % Cut-off frequency
B = fir1(N,Fcut/(Fs/2)) % Filter coefficients in length N+1 vector B

t = [0:L-1]*Ts;         % time array
A_m = 80;               % Amplitude of main component
F_m = 5;                % Frequency of main component
P_m = 80;               % Phase of main component

y_m = A_m*sin(2*pi*F_m*t - P_m*(pi/180));

A_s = 40;               % Amplitude of secondary component
F_s = 40;               % Frequency of secondary component
P_s = 20;               % Phase of secondary component

y_s = A_s*sin(2*pi*F_s*t - P_s*(pi/180));

y = round(y_m + y_s);   % sum of main and secondary components (rounded to integers)

y_filt = round(filter(B,1,y)); % filtered data (rounded to integers)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Serial_port_object = serial(comport);           % create Serial port object
set(Serial_port_object,'InputBufferSize',L)     % set InputBufferSize to length of data
set(Serial_port_object,'OutputBufferSize',L)    % set OutputBufferSize to length of data
fopen(Serial_port_object)                       % open Com Port
fwrite(Serial_port_object,y,'int8');            % send out data
data = fread(Serial_port_object,L,'int8');      % read back data
fclose(Serial_port_object)                      % close Com Port
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

subplot(2,1,1)
hold off
plot(t,y)
hold on
plot(t,y_filt,'r')
plot(t,y_filt,'ro')
plot(t,data,'k.')
ylabel('Amplitude')
legend('y','y filt (PC)','y filt (PC)','y filt (muP)')

subplot(2,1,2)
hold off
plot(t,data'-y_filt)
hold on
xlabel('time')
ylabel('muP - PC')
figure(1)
...