Part Number: MSP432P401R
Tool/software: Code Composer Studio
Hello!,
I am working with the MSP432 to collect data from an accelerometer through the DMA and send it through serial (UART) to my PC. It has been working well so far, until I added the EUSCI interrupt so that the MSP432 could read a byte sent from my PC. Since that moment, I cant read anything from the serial port at my PC and when I debug the code I have notice that after entering the EUSCI interrupt (when a byte is sent from my PC) the DMA interrupt stops working and there is no refreashing of data to buffer_1 and buffer_2 (refer to the code).
I am attaching the code below.
#include <ti/devices/msp432p4xx/inc/msp.h> #include <ti/devices/msp432p4xx/driverlib/driverlib.h> #include <ti/grlib/grlib.h> #include <stdio.h> #include <arm_math.h> #include <arm_const_structs.h> static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32]; /* DMA Control Table */ #if defined(__TI_COMPILER_VERSION__) #pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024) #elif defined(__IAR_SYSTEMS_ICC__) #pragma data_alignment=1024 #elif defined(__GNUC__) __attribute__ ((aligned (1024))) #elif defined(__CC_ARM) __align(1024) #endif // ---------- Variables generales----------- // const char digits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; #define SAMPLE_FREQUENCY 1000 #define SMCLK_FREQUENCY 48000000 static volatile uint16_t DMA_counter = 0; static volatile uint16_t ADC_counter = 0; static volatile uint16_t UART_counter = 0; volatile int mode = 1; volatile int flag = 0; volatile int size = 0; volatile int change_array = 0; volatile int UART_flag = 0; // ---------- FFT Parámetros ----------- // #define N_MUESTRAS 1024 uint32_t fftSize = N_MUESTRAS*4; uint32_t ifftFlag = 0; uint32_t BitReverse = 1; uint32_t max_freq_bin = 0; volatile arm_status status; // ---------- Inicialización de BUFFERS ----------- // float hanning[N_MUESTRAS*2]; int16_t data_buffer1[N_MUESTRAS]; int16_t data_buffer2[N_MUESTRAS]; int16_t data_fft[N_MUESTRAS*8]; int16_t data_out[N_MUESTRAS*4]; int16_t buffer4096[N_MUESTRAS*4]; //------ FIR -------// //#define N_TAPS 25 #define N_TAPS 38 int16_t filter_sum[1]; int16_t filter[1]; float coeff[N_TAPS] = { 0.0006f, 0.0005f, -0.0002f, -0.0016f, -0.0037f, -0.0065f, -0.0092f, -0.0110f, -0.0110f, -0.0082f, -0.0015f, 0.0093f, 0.0243f, 0.0424f, 0.0624f, 0.0821f, 0.0995f, 0.1124f, 0.1193f, 0.1193f, 0.1124f, 0.0995f, 0.0821f, 0.0624f, 0.0424f, 0.0243f, 0.0093f, -0.0015f, -0.0082f, -0.0110f, -0.0110f, -0.0092f, -0.0065f, -0.0037f, -0.0016f, -0.0002f, 0.0005f, 0.0006f }; //Para configurar los siguientes elementos se utilizará la libreria "driverlib". //Las referencias a MAP de esta libreria están en: dev.ti.com/.../rom__map_8h.html void CLOCK_Config(void) { // --------------------------- Configuración del CLOCK --------------------------- // //Elejimos la frecuencia de reloj SMCLK en DC0=48MHz con un prescalador igual a 1. MAP_PCM_setCoreVoltageLevel(PCM_VCORE1); MAP_FlashCtl_setWaitState(FLASH_BANK0, 2); MAP_FlashCtl_setWaitState(FLASH_BANK1, 2); //Elejimos la frecuencia de reloj general DCO en 48MHz. MAP_CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48); //Elejimos la frecuencia de reloj SMCLK en DC0=48MHz con un prescalador igual a 1. MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); //Elejimos la frecuencia de reloj MCLK en DC0=48MHz con un prescalador igual a 1. MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); //Elejimos la frecuencia de reloj HSMCLK en DC0=48MHz con un prescalador igual a 1. MAP_CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); //Elejimos la frecuencia de reloj MCLK en REFOCLOCK=36.6KHz con un prescalador igual a 1. MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1); } void GPIO_Config(void) { // --------------------------- Configuración de GPIO --------------------------- // //Para configurar el ADC de la Tarjeta 1 los puertos de entrada del ADC son P4.0 con canal A13. P4->SEL1 |= BIT0; P4->SEL0 |= BIT0; //Para configurar el ADC de la Tarjeta 2 los puertos de entrada del ADC son P6.0 con canal A15. P6->SEL1 |= BIT0; P6->SEL0 |= BIT0; //Para probar la frecuencia de salida de las interrupciones del ADC, se utiliza el pin P1.0 con salida digital. P1OUT &= ~BIT0; P1DIR |= BIT0; //Para transmitir los datos de forma serial, se elijen los pines P1.2 y P1.3 como TX Y RX respectivamente del UART. P1SEL0 |= BIT2 | BIT3; } const eUSCI_UART_Config uartConfig = { //57600 bps: EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 52, // BRDIV = 52 1, // UCxBRF = 1 0, // UCxBRS = 0 EUSCI_A_UART_NO_PARITY, // No Parity EUSCI_A_UART_LSB_FIRST, // LSB First EUSCI_A_UART_ONE_STOP_BIT, // One stop bit EUSCI_A_UART_MODE, // UART mode EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // Oversampling }; void TIMER_Config(void) { // --------------------------- Configuración del TIMER --------------------------- // // Se configura el Timer para que tenga la señal de reloj como SMCLK de referencia, con un escalador de 1, modo de operación UP // Salida tipo SET-RESET y un periodo de cuenta igual a SMLCK/Frecuencia_de_Muestreo_Deseada. Timer_A_PWMConfig pwmConfig = {TIMER_A_CLOCKSOURCE_SMCLK, TIMER_A_CLOCKSOURCE_DIVIDER_1, (SMCLK_FREQUENCY/SAMPLE_FREQUENCY), TIMER_A_CAPTURECOMPARE_REGISTER_1, TIMER_A_OUTPUTMODE_SET_RESET, (SMCLK_FREQUENCY/SAMPLE_FREQUENCY)/2}; Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig); } void ADC_Config(void) { // --------------------------- Configuración del ADC --------------------------- // //Permite las operaciones de configuración en el ADC. ADC14_enableModule(); //Inicializa el ADC con el DCO=48MHz como reloj de referencia, con un prescalador igual a 1 y escalador igual a 1. ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1, 0); //Se selecciona la salida del TIMER A0 como referencia de disparo para iniciar el muestreo, false = sin invertir la señal de entrada. ADC14_setSampleHoldTrigger(ADC_TRIGGER_SOURCE1, false); //Se selecciona el modo de operación de una sola muestra. Esto se debe a que el ADC iterará la adquisición de datos segun la señal externa de disparo de referencia. //Se escoge el espacio de memoria MEM0 para almacenar cada muestra del ADC, true = se repetirá la conversión al mismo espacio de memoria MEM0. ADC14_configureSingleSampleMode(ADC_MEM0, true); //Se configura el canal A13 del ADC que será muestreado y del cual se almacenará la información en MEM0, false = no se trabaja el ADC en modo diferencial. ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_AVCC_VREFNEG_VSS, ADC_INPUT_A15, ADC_NONDIFFERENTIAL_INPUTS); //Se configura la resolución del ADC en 14 bits, esto implica que cada periodo de muestreo son 16 ciclos de reloj de clock. ADC14_setResolution(ADC_14BIT); } void DMA_Config(void) { // --------------------------- Configuración del DMA --------------------------- // //Permite las operaciones de configuración en el DMA. DMA_enableModule(); //Define la estructura de control del DMA. Esta tabla se encuentra en memoria. DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable); //Define la estructura de control del DMA. Esta tabla se encuentra en memoria. DMA_disableChannelAttribute(DMA_CH7_ADC14, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CH7_ADC14, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH7_ADC14, UDMA_MODE_PINGPONG, (void*) &ADC14->MEM[0], data_buffer1, N_MUESTRAS); MAP_DMA_setChannelControl(UDMA_ALT_SELECT | DMA_CH7_ADC14, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); MAP_DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH7_ADC14, UDMA_MODE_PINGPONG, (void*) &ADC14->MEM[0], data_buffer2, N_MUESTRAS); //Configurar e inicializar interrupciones. MAP_DMA_assignInterrupt(DMA_INT1, 7); MAP_Interrupt_enableInterrupt(INT_DMA_INT1); MAP_DMA_assignChannel(DMA_CH7_ADC14); MAP_DMA_clearInterruptFlag(7); } void TransmitirDatos() { int j=0; for (j=0;j < size; j++) { while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = digits[(data_out[j])>>12]; while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = digits[0xF & ((data_out[j])>>8)]; while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = digits[0xF & ((data_out[j])>>4)]; while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = digits[0xF & ((data_out[j]))]; while(!(UCA0IFG & UCTXIFG)); UCA0TXBUF = '\n'; UART_counter++; } } int main(void) { // ---------- Funciones de configuración e inicialización del sistema ---------- // //Parar el reloj WDT. MAP_WDT_A_holdTimer(); MAP_Interrupt_disableMaster(); CLOCK_Config(); GPIO_Config(); TIMER_Config(); ADC_Config(); DMA_Config(); MAP_Interrupt_enableMaster(); MAP_DMA_enableChannel(7); MAP_ADC14_enableConversion(); MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig); MAP_UART_enableModule(EUSCI_A0_BASE); MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT); MAP_Interrupt_enableInterrupt(INT_EUSCIA0); MAP_Interrupt_enableSleepOnIsrExit(); MAP_Interrupt_enableMaster(); //Inicializar Filtro FIR de tipo Hamming Window: //Referencia:www.allaboutcircuits.com/.../ int n; for(n = 0; n < N_MUESTRAS*2; n++) { hanning[n] = 0.5 - 0.5 * cosf((2 * PI * n) / ((N_MUESTRAS*2) - 1)); } while(1) { //Duerme hasta la interrupción del DMA. //Medido con el Ociloscoipo: Se envía el buffer de datos cada 1000ms. //P1->OUT = BIT0; MAP_PCM_gotoLPM0(); //P1->OUT &= ~BIT0; int i = 0; int j = 0; int z = 0; if (UART_flag == 1) { switch (mode) { case 1: { size = N_MUESTRAS; if(change_array & 1) { for(i = 0; i < N_MUESTRAS; i++) { data_out[i] = data_buffer1[i]; } TransmitirDatos(); } else { for(i = 0; i < N_MUESTRAS; i++) { data_out[i] = data_buffer2[i]; } TransmitirDatos(); } break; } case 2: { size = N_MUESTRAS; if(change_array & 1) { P1->OUT = BIT0; //81ms for(i=0; i < N_MUESTRAS; i++) { filter_sum[0] = 0; for(j=0; j < N_TAPS; j++) { if ((i-j)<0) { filter_sum[0]=data_buffer1[i]; } else { filter[0] = (int16_t)(coeff[j] * data_buffer1[i-j]); filter_sum[0] = filter_sum[0] + filter[0]; } } data_out[i] = filter_sum[0]; } P1->OUT &= ~BIT0; TransmitirDatos(); } else { //P1->OUT = BIT0; for(i=0; i < N_MUESTRAS; i++) { filter_sum[0] = 0; for(j=0; j < N_TAPS; j++) { if ((i-j)<0) { filter_sum[0]=data_buffer2[i]; } else { filter[0] = (int16_t)(coeff[j] * data_buffer2[i-j]); filter_sum[0] = filter_sum[0] + filter[0]; } } data_out[i] = filter_sum[0]; } //P1->OUT &= ~BIT0; TransmitirDatos(); } break; } case 3: { if(change_array & 1) { for(i=0; i < N_MUESTRAS; i++) { filter_sum[0] = 0; for(j=0; j < N_TAPS; j++) { if ((i-j)<0) { filter_sum[0]=data_buffer1[i]; } else { filter[0] = (int16_t)(coeff[j] * data_buffer1[i-j]); filter_sum[0] = filter_sum[0] + filter[0]; } } buffer4096[i] = filter_sum[0]; } } else { z=N_MUESTRAS; flag=1; for(i=0; i < N_MUESTRAS; i++) { filter_sum[0] = 0; for(j=0; j < N_TAPS; j++) { if ((i-j)<0) { filter_sum[0]=data_buffer2[i]; } else { filter[0] = (int16_t)(coeff[j] * data_buffer2[i-j]); filter_sum[0] = filter_sum[0] + filter[0]; } } buffer4096[z] = filter_sum[0]; z++; } } if (flag==1) { for(i = 0; i < N_MUESTRAS*2; i++) { buffer4096[i] = (int16_t)(hanning[i] * buffer4096[i]); } for(i = (N_MUESTRAS*2); i < N_MUESTRAS*4; i++) { buffer4096[i] = 0; } arm_rfft_instance_q15 instance; status = arm_rfft_init_q15(&instance, fftSize, ifftFlag, BitReverse); arm_rfft_q15(&instance, buffer4096, data_fft); for(i = 0; i < (N_MUESTRAS*4); i = i+2) { data_out[i/2] = (int16_t)(sqrtf((data_fft[i] * data_fft[i]) + (data_fft[i+1] * data_fft[i+1]))); } data_out[0]=15; data_out[1]=15; data_out[2]=15; data_out[3]=15; size = 205; TransmitirDatos(); flag=0; } break; } } } } } /* Completar una interrupción para ADC14 MEM0 */ void DMA_INT1_IRQHandler(void) { DMA_counter++; if(DMA_getChannelAttribute(7) & UDMA_ATTR_ALTSELECT) { change_array = 1; DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CH7_ADC14, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH7_ADC14, UDMA_MODE_PINGPONG, (void*)&ADC14->MEM[0], data_buffer1, N_MUESTRAS); } else { change_array = 0; DMA_setChannelControl(UDMA_ALT_SELECT | DMA_CH7_ADC14, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH7_ADC14, UDMA_MODE_PINGPONG, (void*)&ADC14->MEM[0], data_buffer2, N_MUESTRAS); } } /* Completar una interrupción para EUSCIA0 */ void EUSCIA0_IRQHandler(void) { uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE); MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status); if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) { //MAP_UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE)); if (MAP_UART_receiveData(EUSCI_A0_BASE)==65) { P1->OUT = BIT0; UART_flag=1; } else { P1->OUT &=~BIT0; UART_flag=0; } } }
I think it has to do with the order I am entering the interrupts configuration, but I am not sure.
Thanks a lot in advance.
David.