Workaround for the interrupt routines

26 Jan 2011

I need to get 3 serial channels working. They are working individually but I have serious problem to get them to work together so I started to write directly to the UARTs registers. It seems to work but at wrong speed. I need to know at what frequency the peripherals are running at to calculate the register settings.

I know they are normally set to 1/4 of the CPU speed which is supposed to be 100Mhz. I also know there is a way to measure the CPU clock speed but it's a little tricky for me to hit the tiny pin.

So does anybody know the frequencies for the UARTs?

26 Jan 2011

The Mbed CPU clock is 96Mhz not 100Mhz. See this for more info. [Edit: you may also find this useful]

26 Jan 2011

Hi Jacob,

A CMSIS variable called SystemCoreClock contains the core clock frequency, so you can just use that in your calculations or print it out to see the value. For example:

#include "mbed.h"

int main() {
    printf("SystemCoreClock = %d Hz\n", SystemCoreClock);
}

You can then set things like the UART peripheral clock divider (defaults to /4) and the UART internal dividers based on this to get what you want. Andy's examples are a good reference.

Simon

27 Jan 2011

Ok thank you.

For those who like to measure, this is what needs to be done:

void show_clock_on_pin(void){

PINSEL3 |= 0x400000; CLKOUTCFG |= 0x100;

}

27 Jan 2011

I am now happily back on track a little.

I made a dump of the register for the clock to peripherals:

  1. define PCLKSEL0 0x400FC1A8

int *p_reg;

p_reg = (int *) PCLKSEL0;

i = *p_reg;

printf("SystemCoreClock = %d Hz\n", SystemCoreClock); printf("PCLKSEL0 = %x \n", i);

I should have realised by Andys code that the UART0 is running on CPUclock/1

I like to go forward with a second interrupt routine, can I use the attach method or do I have to fix this with the hardware registers to avoid hanging?

01 Feb 2011

So now I wrote a very simple interrupt routine:

void rxCallback_Zigbee(void) { static int c;

c++;

if(c == 10) mled1 = 1;

if(c >= 20){

c = 0; mled1 = 0;

} } It will make the led blink for some seconds and then go "dead# the background routine and the other serial routine has similar blinking which are "alive". The ports are run at 38400 so I should have some 250 000 cycles between each interrupt.

Does anybody have some ideas on how to go further?

02 Feb 2011

Sorry one hour spinning and the famous Bedarö bitter made me miscalculate. It is actually 25 000 cycles, still a lot of cycles.

02 Feb 2011

Hi Jacob,

That routine itself looks fine. Do you have any more context?

Perhaps you have other things that are going wrong which could either stop you getting rx characters hence no interrupts, or something else starts taking up all the processing time so this routine never gets executed?

Simon

02 Feb 2011

This is the other callback routine:

void rxCallback(void) {

static char nmea_in; extern volatile int rec_state; extern volatile char Rx_buffer[2000]; extern volatile int p_rx; extern volatile int ais_ready; int head;

Rx_buffer[p_rx++] = bg2.getc();

mled0 = 1;

nmea_in= bg2.getc();

switch (rec_state) {

case IDLE:

mled0 = 1;

break;

case SEARCH_START:

if (nmea_in == '$') {

mled1 = 1;

rec_state = CAPTURE;

}

break;

case CAPTURE:

garmin_buffer[item++] = nmea_in;

if(item >6){

head = analyze_buffer();

if(head == 17){

mled2 = 1;

gi++;

if(gi >= 2){

gi = 0;

mled0 = 0; mled1 = 0; mled2 = 0; mled3 = 0;

}

rec_state = FETCH_DATA; we found our nmea sentence

}

else{

rec_state = SEARCH_START; not rigth sentence, go back to search rigth header

item = 0;

} }

break;

case FETCH_DATA:

garmin_buffer[item++] = nmea_in;

if(item > 40){

packet_data_no_printf();

print_bg(&ais_2_garmin[0]); print_pc(&ais_2_garmin[0]);

item = 0;

ais_ready = 17;

rec_state = SEARCH_START;

NVIC_DisableIRQ(UART2_IRQn);

} break;

DEFAULT:

mled0 = 1;

break; }

if(p_rx > 1100){ p_rx = 1100; mled2 = 0; }

}

There is a remainder " NVIC_DisableIRQ(UART2_IRQn); " that looks like it can do some harm, but it's actually disabling itself (wich doesn't happen.

I will try to remove it this evening, there is also a "mled1 = 0;" line wich I missed wich is probably the fault.

Ok thank you I have some hope for the future.

02 Feb 2011

The simple solution to this was to actually read the incoming character in the interrupt routine. I missed out on that. Better not do anything more today.