I try to make a DMA UART transfer and it works ok. But the problem is in the program i try to put an Intrerrupt for DMA Complete but it doesn't work the interrupt, when I check with the debugger the status for registers them looks ok. Then i tryed to make a button interrupt without MQX GIPIO driver only hardware interrupt. But this to don't work.
The function int_install_isr it's returning the value for ISR ok, i don't receive a NULL pointer.
THis matter drive me crazy !!
Then I try to build my interrupt configuration based on isr.c example from MQX examples.
This is the code for ISR
void sw2_isr(pointer user_isr_ptr){ MY_ISR_STRUCT_PTR isr_ptr; isr_ptr = (MY_ISR_STRUCT_PTR)user_isr_ptr; /* Chain to the previous notifier */ (*isr_ptr->OLD_ISR)(isr_ptr->OLD_ISR_DATA); printf("SW2 ISR\n"); PORTE_ISFR=0xFFFFFFFF; //Clear Flags on Port E ISR Flag Register}//ANd DMA ISR CODEvoid dma5_isr(pointer data){ if(DMA_ES_REG(DMA_BASE_PTR)&DMA_ES_VLD_MASK == 1) printf("Eroarre"); else printf("Intrerupere"); DMA_CERQ=DMA_CERQ_CERQ(5); DMA_CINT=DMA_CINT_CINT(5); }
And This is the code for the task and initialization of the isr's functions
void uart5_dma_task(uint_32 data){ //Local Variables MY_ISR_STRUCT_PTR isr_ptr; MQX_FILE_PTR port_file_sw1; int *isr; uint8_t uint8_dma_channel=5; char c,i=0; enable_dma_clocks(); gpio_init_isr_porte(); /* port_file_sw1=fopen("gpio:input",(char *)&SW1); if(port_file_sw1!=NULL) {printf("IRQ 1 SET\n"); _io_ioctl(port_file_sw1,GPIO_IOCTL_SET_IRQ_FUNCTION,(char *)irq_sw1);}*/ //Enable DMA Channel 5 with UART5-RX (12) intrerrupt surce. enable_dmamux(uint8_dma_channel,UART5_DMA_RX_DMAMUX); uart5_dma_init(UART5_BASE_PTR,BSP_BUS_CLOCK_KHZ,UART5_BAUD_RATE); isr_ptr = _mem_alloc_zero((_mem_size)sizeof(MY_ISR_STRUCT)); isr_ptr->OLD_ISR_DATA =_int_get_isr_data(INT_PORTE); isr_ptr->OLD_ISR=_int_get_isr(INT_PORTE); if(!_int_install_isr(INT_PORTE, sw2_isr, isr_ptr)) printf("Esuare Instalare ISR\n"); isr_ptr->OLD_ISR=_int_get_isr(DMA5_ISR_VECTOR); if(!_int_install_isr(DMA5_ISR_VECTOR,dma5_isr,isr_ptr)) printf("Esuare Instalare DMA5 ISR\n"); printf("ISR NEINITIALIZAT=0x%x\n",isr); isr=(int *)_int_get_isr(DMA5_ISR_VECTOR); printf("ISR pentru DMA5 =0x%x\n",isr); isr=(int *)_int_get_isr(UART5_RX_TX_ISR_VECTOR); printf("ISR pentru UART5 =0x%x\n",isr); uart_putchar(UART5_BASE_PTR,'c'); dma_config_start(uint8_dma_channel); _int_enable(); while(1) { }}
And the header and defines are here used in the uart5_dma_task :
#define UART5_RX_TX_ISR_VECTOR 71#define DMA5_ISR_VECTOR 21#define PORTE_ISR_VECTOR 107#define UART5_DMA_RX_DMAMUX 12#define UART5_DMA_TX_DMAMUX 13#define BUFFER_LENGHT 100#define SW_1 (GPIO_PORT_A | GPIO_PIN19)#define SW_2 (GPIO_PORT_E | GPIO_PIN26)void uart5_dma_init(UART_MemMapPtr uartch, int sysclk, int baud);extern void uart5_dma_task(uint_32 data);extern void isr_dma5( void );extern void uart_isr( UART_MemMapPtr base );extern void sw2_isr(pointer);
I solved the problem, it was something about setting priority level in NVIC(nested vector interrupt controller) more than 7.
So I made 2 additional functions to set_irq_priority and to do enable_irq.
void enable_irq (int irq){ int div; /* Make sure that the IRQ is an allowable number. Right now up to 91 is * used. */ if (irq > 91) printf("\nERR! Invalid IRQ value passed to enable irq function!\n"); /* Determine which of the NVICISERs corresponds to the irq */ div = irq/32; switch (div) { case 0x0: NVICICPR0 = 1 << (irq%32); NVICISER0 = 1 << (irq%32); break; case 0x1: NVICICPR1 = 1 << (irq%32); NVICISER1 = 1 << (irq%32); break; case 0x2: NVICICPR2 = 1 << (irq%32); NVICISER2 = 1 << (irq%32); break; } }
And the one to set priority:
void set_irq_priority (int irq, int prio){ /*irq priority pointer*/ uint_8 *prio_reg; /* Make sure that the IRQ is an allowable number. Right now up to 91 is * used. */ if (irq > 91) printf("\nERR! Invalid IRQ value passed to priority irq function!\n"); if (prio > 15) printf("\nERR! Invalid priority value passed to priority irq function!\n"); /* Determine which of the NVICIPx corresponds to the irq */ prio_reg = (uint_8 *)(((uint_32)&NVICIP0) + irq); /* Assign priority to IRQ */ *prio_reg = ( (prio&0xF) << (8 - ARM_INTERRUPT_LEVEL_BITS) ); }
So now all my interrupts are working how I want them to work !!
But another problem came to my attention when I use the DMA transfer on circular queue and the Destination modulo 2 address incremented with offset 1 byte. To transfer data from UART5 Data register, if the start address of the buffer variable is not aligned to a modulo 2 address. It's going to cut from your space available for buffer elements.
Exemple
If i have a modulo 2 bits for incrementing the destination address and the start address for buffer is 0xfffff350
I have 0xfffff350 first element
0xfffff351 second one
0xfffff352 3th
0xfffff353 4th one
and if the compiler allocates the start address for the buffer the address 0xfffff352
I remain only with 2 available locations for my buffer to store my data's because the modulo 2 feature let me to increment only the last 2 bits from the start address of the buffer.
So my question is how can I determine the compiler to allocate in memory my buffer to start at the right address.
This is the code for DMA configuration
/********************************************************************//* * Configuration of DMA_channel and start of the movement data from * UART5 Data register address and to a queue(circular stack) with the * beginning address of the buffer variable as a destination address. * The destination address will be incremented with the width of the transfered * data in bytes from the source address in this case sizeof the UART5 Data register * */void dma_config_start(uint_8 channel){ DMA_CITER_ELINKNO_REG(DMA_BASE_PTR,channel)=DMA_BITER_ELINKNO_REG(DMA_BASE_PTR,channel)=sizeof(UART5_D); DMA_NBYTES_MLNO_REG(DMA_BASE_PTR,channel)=sizeof(UART5_D); DMA_SOFF_REG(DMA_BASE_PTR,channel) = 1; DMA_SADDR_REG(DMA_BASE_PTR,channel)=(uint_32)&UART5_D; DMA_ATTR_REG(DMA_BASE_PTR,channel)=DMA_ATTR_SMOD(0)|DMA_ATTR_SSIZE(0)|DMA_ATTR_DMOD(2)|DMA_ATTR_DSIZE(0); DMA_SLAST_REG(DMA_BASE_PTR,channel)=-sizeof(UART5_D); DMA_DADDR_REG(DMA_BASE_PTR,channel)=(uint_32)&buffer; DMA_DOFF_REG(DMA_BASE_PTR,channel) = sizeof(UART5_D); DMA_DLAST_SGA_REG(DMA_BASE_PTR,channel) = 0; DMA_SERQ_REG(DMA_BASE_PTR)=DMA_SERQ_SERQ(5); DMA_ERQ_REG(DMA_BASE_PTR) |=(1<<channel); DMA_CR |=DMA_CR_EDBG_MASK; //Enable Debug MODE in DMA //DMA_INT_REG(DMA_BASE_PTR) |=DMA_INT_INT5_MASK; DMA_CSR_REG(DMA_BASE_PTR,channel)=DMA_CSR_INTMAJOR_MASK; //DMA_CSR_START_MASK;}
Hi Nana.
Sorry for your hassles but thank you for sharing your code and experience. It will benefit others trying to do the similar work.
Best Regards,
David
Now i have another problem after upgrade to CW 10.2 and MQX 3.8 it seems my ISR don't wana work any more, no one.
The problem is after installing the corresponding ISR in vector table , and reading ok the address for the ISR.
And writing to NVIC register to enable interrupts it seems is not working the MQX activates only the interrupt for timer ! And my interrupt for PORTE are disabled NVICSER2 all the time is 04 and must be 0x8000000 corresponding for PORTE int witch is 91.
And if i set in debug mode the corresponding registers for enable interrupts in NVIC, and activate it manually the ISR kernel Handler send me to the location of default_isr (this is running in desasambled code)
My question is the compiler make some optimization for the new version of CW?
Hi Nana,
could you simply explain what is your intention with interrupts? I'm sorry but It's really hard to understand your post.
Regards,
MartinK
Now I made a simple new project where I want to use interrupts for Sw1 and Sw2 buttons on my twr-k60n512 board what are connected as ..
SW1 ----> PTA19
SW2 ----> PTE26
So I made my configuration as SW1 used with MQX GPIO driver and installed interrupt with ioctl command. This seems to work OK. But the second one I want to install as a normal interrupt. So i activate the PIN interrupt and this is okey it's detecting de interrupt, because watching the registers in PORTE_PCR26 the interrupt flag is set when the button is pressed.
And in NVIC interrupt controller module is detecting de flag by seting the NVICSPR2 0x8000000 register with the bit coresponding to PORTE interup IRQ.
So the problem is the MQX don't install the ISR adress to my interrupt function I belive: i'm geting all the time from install_isr function the address for default_isr
Here it is my code:
#include "main.h"#include <mqx.h>#include <bsp.h>typedef struct my_isr_struct{ pointer OLD_ISR_DATA; void (_CODE_PTR_ OLD_ISR)(pointer);} MY_ISR_STRUCT, _PTR_ MY_ISR_STRUCT_PTR;TASK_TEMPLATE_STRUCT MQX_template_list[] ={/* Task number, Entry point, Stack, Pri, String, Auto? */ {MAIN_TASK, Main_task, 2000, 9, "main", MQX_AUTO_START_TASK}, {0, 0, 0, 0, 0, 0, }};void sw2_isr(pointer data){printf("ISR Works\n");PORTE_ISFR=0xFFFFFFFF;}void gpio_init_isr_porte(void) { SIM_SCGC5 |=SIM_SCGC5_PORTE_MASK; PORTE_PCR26=PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA)|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK; } void Main_task(uint_32 initial_data){ pointer result;MY_ISR_STRUCT_PTR isr_ptr;gpio_init_isr_porte();isr_ptr = _mem_alloc_zero((_mem_size)sizeof(MY_ISR_STRUCT));isr_ptr->OLD_ISR_DATA = _int_get_isr_data(INT_PORTE); isr_ptr->OLD_ISR = _int_get_isr(INT_PORTE); result=_int_install_isr(INT_PORTE,( pointer )sw2_isr, isr_ptr); if(result==NULL) printf("Failed to install ISR"); else if(result==_int_get_default_isr()) printf("Default ISR installed\n"); printf("ISR Installed = 0x%x",result); NVICICPR2 = 1 << (91%32); NVICISER2 = 1 << (91%32); /******************************* * * START YOUR CODING HERE * ********************************/ for (;;) { }}/* EOF */
Hi Nana,
please check lwgpio example where one button is used in interrupt mode.
You have to set the interrupt level e, and unmask the interrupt in interrupt controller with a function in your example code :
_bsp_int_init(INT_PORTE, 3, 0, TRUE);
It works!
Regards,
MartinK
I have a question about interrupts: If exist a method to check if the all interrupts are enabled or not ?
Something like int_disabled have ben activa or int_enabled ?
isr_tempo = _mem_alloc_zero((_mem_size)sizeof(MY_ISR_STRUCT));;//alloca un po di memoria per gestire l'interrupt isr_tempo->TICK_COUNT = 0; isr_tempo->OLD_ISR_DATA = _int_get_isr_data(BSP_TIMER_INTERRUPT_VECTOR); isr_tempo->OLD_ISR = _int_get_isr(BSP_TIMER_INTERRUPT_VECTOR); _int_install_isr(BSP_TIMER_INTERRUPT_VECTOR, timer_isr, isr_tempo);void timer_isr(pointer user_isr_ptr){ MY_ISR_STRUCT_PTR isr_ptr; isr_ptr = (MY_ISR_STRUCT_PTR)user_isr_ptr; isr_ptr->TICK_COUNT++; if(isr_ptr->TICK_COUNT % 3) colpi_tempo++; // Chain to the previous notifier // (*isr_ptr->OLD_ISR)(isr_ptr->OLD_ISR_DATA); //why isr_ptr->OLD_ISR_DATA is NULL????}
But also I have a question relating to the example of the interrupt.
Because the example calls _int_get_isr_data when the return value is NULL?
Hello,
Simillar problem here i am facing. Only timer interrupt working. We are trying here for ADC Limit interrupt, but we are facing the problem in interrupt ISR. We are enabling the interrupt in ADC->CR1, ADC->CR2. and getting the interrupt for the same in Interrupt Mask register. It is not setting in IPR.
Below is sample code for code warrior CW 10 and MQX 4.0 given in $ Freescale_MQX_4_0\mqx\source\io\adc\mcf544xx
old_isr_adc1_param = _int_get_isr(BSP_ADC_INTERRUPT_VECTOR);
old_isr_adc1 = _int_install_isr(BSP_ADC_INTERRUPT_VECTOR, adc_complete_isr, NULL);
_mcf5441_int_init(BSP_ADC_INTERRUPT_VECTOR, BSP_ADC_INTERRUPT_LEVEL, TRUE);
Kindly Help.