This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS1224: vimEnableInterrupt / vimDisableInterrupt Functions Not Working to Enable/Disable Interrupts

Part Number: TMS570LS1224
Other Parts Discussed in Thread: HALCOGEN

Tool/software:

Hi,

I am trying to use the functions vimEnableInterrupt and vimDisableInterrupt to enable or disable a specific interrupt vector. In my case, it’s for adcGROUP1.

However, I cannot make it work. It seems that the interrupt for adcGROUP1 is never enabled by the instruction vimEnableInterrupt(15, SYS_IRQ).

Below, I have attached the sys_main.c and notification.c files so you can take a look. Thank you for your assistance with this issue.

sys_main.c

/* Include Files */

#include "sys_common.h"

/* USER CODE BEGIN (1) */
#include "adc.h"
#include "sci.h"
#include "gio.h"
#include "stdlib.h"
#include "stdio.h"
#include "sys_vim.h"
/* USER CODE END */

/** @fn void main(void)
* @brief Application main function
* @note This function is empty by default.
*
* This function is called after startup.
* The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */

/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */

sciInit();
adcInit();
gioInit();
//_enable_IRQ();
vimInit();

vimEnableInterrupt(15, SYS_IRQ);
// vimChannelMap(15, 15, adc1Group1Interrupt);
//vimDisableInterrupt(15);

adcEnableNotification(adcREG1, adcGROUP1);
/* start adc conversion */
adcStartConversion(adcREG1, adcGROUP1);
printf("\n");
fflush(stdout);

while (1)

{
gioSetBit(gioPORTB, 0, 1);
printf("Sen by Serial Port \n");
fflush(stdout);
gioSetBit(gioPORTB, 0, 0);

}
/* USER CODE END */

return 0;
}


/* USER CODE BEGIN (4) */
/* USER CODE END */

notification.c

/* Include Files */

#include "esm.h"
#include "sys_selftest.h"
#include "adc.h"
#include "gio.h"
#include "sci.h"
#include "sys_dma.h"

/* USER CODE BEGIN (0) */
#include "stdio.h"
#include "stdlib.h"
#include "sys_vim.h"

#pragma WEAK(adcNotification)
void adcNotification(adcBASE_t *adc, uint32 group)
{
/* enter user code between the USER CODE BEGIN and USER CODE END. */
/* USER CODE BEGIN (11) */


adcData_t adc_data;
adcData_t *ptr;
uint32 i = 0;
uint32 c = 0;


c = adcGetData(adcREG1, adcGROUP1, &adc_data);

ptr = &adc_data;

for (i = 0; i < c; i++)
{

printf("adc value[%d]: %d;\n", i, ptr->value);
fflush(stdout);
ptr++;

}


//vimDisableInterrupt(15);


return;

/* USER CODE END */
}

Halcogen

  • Hi Ariel,

    //_enable_IRQ();

    Why did you comment this enable IRQ API?

    This API is very important in VIM interrupt generation, without this API the interrupt may not get generate.

    --
    Thanks & regards,
    Jagadish.

  • Hi Jagadish,

    Thank you for your time and support.

    I commented out the line _enable_IRQ(); because I assumed it enables all IRQs, whereas vimEnableInterrupt(15, SYS_IRQ) enables only the ADC Group1 IRQ.

    In general, my software is designed to enable the ADC Group1 interrupt once and then disable it inside the adcNotification(adcBASE_t *adc, uint32 group) interrupt API.

    The main code runs once, after which the IRQ vector calls the interrupt API and disables the IRQ vector using the line vimDisableInterrupt(15);. This API also executes once and does not return to the main code.

    The overall idea is that the main code runs, and when an interrupt is triggered by ADC Group1, the interrupt API disables the IRQ and returns to the main code.

    I look forward to your feedback.

    THX!

    Ariel G Garcia

  • Hi Ariel,

    _enable_IRQ is required to get any interrupt, so my suggestion is use this api by default in initialization code, and now you can diable or enable the individual interrupt using vimDisableInterrupt and vimEnableInterrupt respectively whenever you needed in the code after initializations.

    --

    Thanks & regards,

    Jagadish.

  • Hi Jagadish.,

    I applied your suggestion to my code, and now the interrupt can be enabled/disabled using vimEnableInterrupt and vimDisableInterrupt. However, I have encountered another problem: the interrupt works fine, but the code never returns to the main routine. I am not sure what is causing this issue.

    Could you please give me a hand? I have reviewed the TMS570LS12x/11x 16/32-Bit RISC Flash Microcontroller Technical Reference Manual, but I couldn't fully grasp the VIM-related details.

    Your guidance would be greatly appreciated.

    Best regards !

     Ariel G Garcia

  • Hi Ariel,

    Can you please verify the value of the GxINTFLG register in the handler? because i am suspecting maybe we are getting overrun error?

    In continuous mode there is a possibility for this error.

    Can you please verify the below thread once, here i mentioned more details about this error.

    (+) LAUNCHXL2-570LC43: ADC continuous conversion mode using interrupts, overrun flag being set - Arm-based microcontrollers - INTERNAL forum - Arm-based microcontrollers - INTERNAL - TI E2E support forums

    --

    Thanks & regards,
    Jagadish.

  • Hi,

    It seems that there is an overrun error in continuous conversion mode. The interrupt is executed only once.

    I have copied the main code along with the debugging section to monitor the OVERRUN bit in the INTFLG register. However, I am unsure how to resolve this issue. Additionally, the link to the thread is not working (Page Not Found).

    Your guidance would be greatly appreciated.

    Best regards,

    Ariel G Garcia

    main code


    /* Include Files */

    #include "sys_common.h"

    /* USER CODE BEGIN (1) */
    #include "adc.h"
    #include "sci.h"
    #include "gio.h"
    #include "stdlib.h"
    #include "stdio.h"
    #include "sys_vim.h"
    uint32 cont_int = 0;
    /* USER CODE END */

    /** @fn void main(void)
    * @brief Application main function
    * @note This function is empty by default.
    *
    * This function is called after startup.
    * The user can use this function to implement the application.
    */

    /* USER CODE BEGIN (2) */

    /* USER CODE END */

    int main(void)
    {
    /* USER CODE BEGIN (3) */

    sciInit();
    adcInit();
    gioInit();
    _enable_IRQ();
    vimInit();
    uint32 i = 0;
    uint32 cont = 0;
    uint32 Conversion = 0;
    uint32 OVERRUN = 0;

    //vimEnableInterrupt(15, SYS_IRQ);
    // vimChannelMap(15, 15, adc1Group1Interrupt);
    //vimDisableInterrupt(15);

    adcEnableNotification(adcREG1, adcGROUP1);
    /* start adc conversion */
    adcStartConversion(adcREG1, adcGROUP1);

    while (1)

    {
    cont = cont+1;
    for (i = 0; i < 1000; i++); // Delay to watch the LED blink
    gioSetBit(gioPORTB, 1, 0);

    if(adcIsConversionComplete(adcREG1, adcGROUP1)==8)
    {
    Conversion =8;
    }else{Conversion =0;}

    if(G1_MEM_OVERRUN(adcREG1, adcGROUP1)==2)
    {
    OVERRUN =2;
    }else{OVERRUN =0;}

    // OVERRUN = G1_MEM_OVERRUN(adcREG1, adcGROUP1);
    //Indicador = adcIsConversionComplete(adcREG1, adcGROUP1);
    // printf("\n");
    //fflush(stdout);
    // gioSetBit(gioPORTB, 0, 0); // Stop convertion
    //adcStartConversion(adcREG1, adcGROUP1);

    }
    /* USER CODE END */

    return 0;

  • Hi,

    First i want to make sure this,

    Are you setting any breakpoints in the interrupt handler for your testing's? If you do that then that might also cause the overrun error, we can ignore this kind of overrun error because it is due to the breakpoints?

    So, what i want to suggest you is that don't set any breakpoints in the handlers. Instead of just read your data continuously and print it on UART terminal, if we are getting the data continuously without any issues then we can assume that the code is running correctly.

    The other way is that copy the data into one buffer continuously, we the buffer is updating with new values continuously then we can assume that the code is running correctly.

    --
    Thanks & regards,
    Jagadish.

  • If you operate in one-shot mode then we can set the breakpoints in the code, because the conversion will happen only after we called start conversion API. So, we can set breakpoint before calling this API and can see the data for each sample in debug mode with breakpoints. However, it is not good to view the data with breakpoints for continuous mode because if we set the breakpoint that will not stop the background ADC conversion, so this will create the overrun errors.

  • Hi Jagadish.

    I have been working on your suggestions and have implemented the new code below. The main loop executes once, and then the interrupt takes over. On the terminal, the string "Helloooooo-----!!!!" is displayed, followed by all the ADC conversion data in continuous mode (like a loop). However, the program never returns from the interrupt.

    Thx & Regars

    The code:

    /* Include Files */

    #include "sys_common.h"

    /* USER CODE BEGIN (1) */
    #include "adc.h"
    #include "sci.h"
    #include "gio.h"
    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    #include "sys_vim.h"
    /* USER CODE END */

    /** @fn void main(void)
    * @brief Application main function
    * @note This function is empty by default.
    *
    * This function is called after startup.
    * The user can use this function to implement the application.
    */

    /* USER CODE BEGIN (2) */
    //-----Serial Port Variable-----------------------------------------------------------------------------------------
    static char Tx[5]; // array de 5 elementos para enviar los digitos del ADC rango 12 bits 0-4095 (es decir, hasta 4 dígitos decimales).

    //--------------------------------------------------------------------------------------------------------------------------------------

    //----Conversor Variables------------------------------------

    adcData_t adc_data; // ADC DAta Structure
    adcData_t *ptr = &adc_data; // ADC Data Pointer
    //---------------------------------------------------------------

    /* USER CODE END */

    int main(void)
    {
    /* USER CODE BEGIN (3) */
    sciInit();
    adcInit();
    gioInit();
    vimInit();
    _enable_IRQ();

    adcEnableNotification(adcREG1, adcGROUP1);
    /* start adc conversion */
    adcStartConversion(adcREG1, adcGROUP1);

    while (1)
    {
    volatile int i;
    sciSend(scilinREG, 25, (unsigned char*) "Helloooooo-----!!!!");
    for (i = 0; i < 1000000; i++);

    }

    /* USER CODE END */

    return 0;
    }

    /* USER CODE BEGIN (4) */
    void adcNotification(adcBASE_t *adc, uint32 group)
    {
    adcStopConversion(adcREG1, adcGROUP1);
    adcGetData(adcREG1, adcGROUP1, ptr);
    sprintf(Tx, "%d", ptr->value); // Data Conversion buffer to String Tx
    sciSend(scilinREG, strlen(Tx), (unsigned char*) &Tx); //strlen(Tx) lenght string Tx
    sciSend(scilinREG, 2, (unsigned char*) "\r\n"); // Send Tx to The Terminal
    adcREG1->GxINTFLG[1U] = 0x1001bU; // clear Interrup Flags
    adcStartConversion(adcREG1, adcGROUP1);
    return;

    }
    /* USER CODE END */

    Halcogen ADC Configuration

  • Hi Ariel,

    I am suspecting this could happen:

    As we select one ADC channel the conversion time is too less, i mean it is converting channel with in 1.6uS. So, what if this is not enough to comeback from interrupt handler and do the execution in the main loop.

    Can you please enable 3 more channels and do the testing once? if still issue is there then i will try to create one new example at my end and will do the further debugging of this issue.

    --
    Thanks & regards,
    Jagadish.

  • Hi Jagadish

    The issue with the interrupt function was caused by calling sprintf inside adcNotification. Since sprintf has a blocking behavior, it caused the execution flow to get stuck inside the interrupt handler. Additionally, the adcStartConversion function must be outside adcNotification because running it inside the interrupt handler creates a loop.

    The solution is to move both sprintf and adcStartConversion out of adcNotification and handle them in the main code instead.

    The correct code is below. Thanks for all your help! I’ve learned a lot from your feedback

    /* USER CODE BEGIN (0) */
    /* USER CODE END */

    /* Include Files */

    #include "sys_common.h"

    /* USER CODE BEGIN (1) */
    #include "adc.h"
    #include "sci.h"
    #include "gio.h"
    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    #include "sys_vim.h"
    /* USER CODE END */

    /** @fn void main(void)
    * @brief Application main function
    * @note This function is empty by default.
    *
    * This function is called after startup.
    * The user can use this function to implement the application.
    */

    /* USER CODE BEGIN (2) */
    //-----Serial Port Variable-----------------------------------------------------------------------------------------
    static char Tx[5]; // array de 5 elementos para enviar los digitos del ADC rango 12 bits 0-4095 (es decir, hasta 4 dígitos decimales).
    //int buffer ; // ADC Data buffer
    //--------------------------------------------------------------------------------------------------------------------------------------

    //----Conversor Variables------------------------------------

    adcData_t adc_data; // ADC DAta Structure
    adcData_t *ptr = &adc_data; // ADC Data Pointer
    //---------------------------------------------------------------
    volatile uint8_t adc_flag = 0;
    /* USER CODE END */

    int main(void)
    {
    /* USER CODE BEGIN (3) */
    sciInit();
    adcInit();
    gioInit();
    vimInit();
    _enable_IRQ();

    adcEnableNotification(adcREG1, adcGROUP1);
    /* start adc conversion */
    adcStartConversion(adcREG1, adcGROUP1);

    while (1)
    {
    volatile int i;
    sciSend(scilinREG, 5, (unsigned char*) "Hola\0");
    for (i = 0; i < 1000000; i++)
    ;
    adcStartConversion(adcREG1, adcGROUP1);

    if (adc_flag) // Solo si hay nueva conversión
    {
    sprintf(Tx, "%d", ptr->value);
    sciSend(scilinREG, strlen(Tx), (unsigned char*) Tx);
    sciSend(scilinREG, 2, (unsigned char*) "\r\n");
    adc_flag = 0; // Reset flag

    adcStartConversion(adcREG1, adcGROUP1); // Ahora sí, iniciar nueva conversión
    }


    }

    /* USER CODE END */

    return 0;
    }

    /* USER CODE BEGIN (4) */
    void adcNotification(adcBASE_t *adc, uint32 group)
    {
    adcStopConversion(adcREG1, adcGROUP1);
    adcGetData(adcREG1, adcGROUP1, ptr);
    adc_flag = 1; // Indicar que hay un nuevo valor listo
    adcREG1->GxINTFLG[1U] = 1U; // Limpiar la interrupción

    }