Allocation of software triggered interrupts

:eek:
................

Why would that be a problem? It is very simple to implement...
I've done this for years, and there's no technical reason why you wouldn't want it.
It is a bit mandatory for doing USB host mode, because you need to allocate objects on-demand.
Sure, you COULD have static stuff all over, but, consider this:
You want to support 6 different joysticks, so that it 'just works' for the person running the application.
You'll probabbly run out of ram very quickly, and you only need one active. Dynamic allocation only makes sense.

https://github.com/xxxajk/xmem2/blob/master/mlock.c has the code that does arm ISR safe malloc/free/etc...
 
You're simply switching off the interrupts, right ?
But that does not mean that you can use it in a swi. Maybe the swi interrupts a malloc in main().
Code:
#ifdef __ISR_SAFE_MALLOC__
noInterrupts();
__isr_safety++;
#endif

Where's my fault ? :)
 
Calling malloc() from an ISR might cause a big increase in interrupt latency? Malloc() can loop looking for a right-sized free block, etc.

First time I've heard/read of someone doing such from an ISR, in the embedded world.
 
.... Once you solve that USB Serial issue and provide a 'none' type for the USB port,

Can you refresh my memory on this particular issue, and perhaps explain in more detail. Or if there's a prior message with all that, just a link to it would be fine.

Whatever this issue is, it's not currently on my TO-DO list.
 
Can you refresh my memory on this particular issue, and perhaps explain in more detail. Or if there's a prior message with all that, just a link to it would be fine.

Whatever this issue is, it's not currently on my TO-DO list.
I forget which particular post it was, but we discussed having a 'none' option in the menu for USB to allow custom code/disable USB. The idea here is to present power savings or custom code.
The problem with doing this with the current code is that the section in 'main.cpp' called Yield which checks serial, which won't be present, thus compile fails.
In short if there is no serial defined, then you need to bypass the checks.

This small fix also resolves the problem when someone selects a CPU speed that does not allow for USB to operate at all, thus you can then add the lower speeds to the menu as well. :cool:
 
Calling malloc() from an ISR might cause a big increase in interrupt latency? Malloc() can loop looking for a right-sized free block, etc.

First time I've heard/read of someone doing such from an ISR, in the embedded world.

I guess that makes it worth noting and newsworthy :)
 
Fun with confused ARM compiler... Oh dear!!

Code:
Bulk Register to USB Host @ 0x1FFF88D4
Bulk Register to USB Host Address Pool @ 0x1FFF88D8

MAX3421E 'this' USB Host @ 0x1FFF88D4
MAX3421E 'this' USB Host Address Pool @ 0x1FFF88DC

Configuring HOST USB Host @ 0x1FFF88D8
Configuring HOST USB Host Address Pool @ 0x1FFF88DC

Bulk Init from USB Host @ 0x1FFF88D4
Bulk Init USB Host Address Pool @ 0x1FFF88D8
Here is what this is showing:
Bulk asked the registering host 'What is the address of the pool' which is the MAX3421E and it gets a wrong reply...
Then in the ISR, the 'this' address is wrong for the correct pool...
HOWEVER it is calling the correct driver instance...
which sees the wrong pool....

I've never seen such convolution before.
The 'this' instance pointer shouldn't be changing, and the pool address shouldn't be changing either.
 
Found a work-around for the bug.
Well, to me it smells like a bug anyway...

This would produce the error...
Code:
class MAX3421E_HOST :
#if defined(SWI_IRQ_NUM)
public dyn_SWI,
#endif
public UHS_USB_HOST_BASE
{
....
}

On a hunch I re-arranged the inheritance to this...

Code:
class MAX3421E_HOST :
public UHS_USB_HOST_BASE
#if defined(SWI_IRQ_NUM)
, public dyn_SWI
#endif
{
....
}

And the results:

Code:
Bulk Register to USB Host @ 0x1FFF88D4
Bulk Register to USB Host Address Pool @ 0x1FFF88D8

MAX3421E 'this' USB Host @ 0x1FFF88D4
MAX3421E 'this' USB Host Address Pool @ 0x1FFF88D8

HOST USB Host @ 0x1FFF88D4
HOST USB Host Address Pool @ 0x1FFF88D8
Bulk Init from USB Host @ 0x1FFF88D4
Bulk Init USB Host Address Pool @ 0x1FFF88D8

Now it is pointing to the correct memory locations. Hrmph!

So, the big question here is why it works this way...
Really, this smells like some sort of strange bug. I should be able to inherit classes in any order I choose, right?
 
Maybe this is a sign you'd be better off with a simple static callback?

Reading
http://www.drdobbs.com/implementing-interrupt-service-routines/184401485

Each ordinary C++ member function has a compiler-generated parameter called this, which is a pointer to an object of the member function’s class type. Each ordinary member function call passes a value for this along with values for any of the function’s explicitly declared parameters. Interrupt handlers are not passed arguments by the host microprocessor, however, so ordinary C++ member functions cannot be used directly as ISRs.

C++ provides the static keyword for defining member functions that do not take a this pointer. A static member function is therefore akin to a typical C function, including its suitability for direct use as an ISR. However, the absence of the this pointer creates the expected limitation: a static member function cannot directly manipulate non-static data members of its class.

let me suggest, that maybe think that the order of inheritance could be important
 
I think in this particular situation, WMXZ is correct. My guess is it is due to how G++ builds the vtable.

In other lagnguages, Java and Python for example, When you inherit something, the table of methods is built after everything is parsed, in such a way that the 'this' object pointer points to everything in that object. It does not always seem to be the case in C++, which leads me to think that there are actually three ways to tackle it.

1: Rearrange the inherited classes so that the base class is the first one.
2: Make an entirely new secondary base class that contains the first two, and provide accessor to each of them, and wrap the calls. (messy)
3: Forget using a base class, but that breaks the ability to have a generic 'this' pointer to pass up the chain, and totally breaks the entire idea of OOP.

In short, I think it is either a real bug, or a bad language design that is biting me. The 'this' pointer should be pointing to the entire object, regardless of how it is declared.

@paul: The actual call is static. I simply tell the function what object instance that I am working with. The interesting bit is that the called object sees yet another instance that matches neither, so this is why I would consider it either a bug, or an undocumented feature of how vtables interact with the this keyword.
 
In other news, I've managed to 'port' the interrupt tester to ATMEL's ARM offerings. It should also work with any ARM-based MCU that uses CMSIS, and contains an NVIC that allows relocation of the vector table.

Here is the output from the test ran on the Zero, output onto the debug port, which allows checking every IRQ, even the USB one. :cool:

Code:
Interrupt tester
28 Interrupts available.
16 (0)...OK.
17 (1)...OK.
18 (2)...OK.
19 (3)...OK.
20 (4)...OK.
21 (5)...OK.
22 (6)...OK.
23 (7)...OK.
24 (8)...OK.
25 (9)...OK.
26 (10)...OK.
27 (11)...OK.
28 (12)...OK.
29 (13)...OK.
30 (14)...OK.
31 (15)...OK.
32 (16)...OK.
33 (17)...OK.
34 (18)...OK.
35 (19)...OK.
36 (20)...OK.
37 (21)...OK.
38 (22)...OK.
39 (23)...OK.
40 (24)...OK.
41 (25)...OK.
42 (26)...OK.
43 (27)...OK.
Done.


I don't own an arduino Due, but I believe that I wrote the code in a way that should interface easily with any ARM using the CMSIS standards, and contains an NVIC that allows for relocating the vectors to RAM, which is most of them, fortunately.

Here is the code, which will still work on the ARM based teensy products, which lack debug.
I'll hopefully be able to get CMSIS working for these, as well as my own board, and capture the debug I/O on my Teensy3.1 based JTAG.



Code:
#if !defined(NVIC_SET_PENDING)
#define NVIC_SET_PENDING(n) NVIC_SetPendingIRQ((IRQn_Type)n)
#endif

#if !defined(NVIC_ENABLE_IRQ)
#define NVIC_ENABLE_IRQ(n) NVIC_EnableIRQ((IRQn_Type)n)
#endif


volatile int chk;
#if defined(CORE_TEENSY)
const unsigned char swInterrupts[] = {
#if defined(__MK20DX128__)
5,
#elif defined(__MK20DX256__)
17,23,28,37,38,39,40,41,42,43,51,52,53,54,55,56,75,76,77,78,79,80,82,86,92,93,
#endif
IRQ_UART0_LON,
IRQ_SOFTWARE,
0};
#else
extern "C" {
#define NVIC_NUM_INTERRUPTS ((int)PERIPH_COUNT_IRQn)
#define VECTORTABLE_SIZE (NVIC_NUM_INTERRUPTS+16)
#define VECTORTABLE_ALIGNMENT (0x100ul)
uint32_t _VectorsRam[VECTORTABLE_SIZE] __attribute__((aligned(VECTORTABLE_ALIGNMENT)));
}
#endif


void softISR() {
        chk = 1;
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        Serial.println("...OK.");
}


void setup() {

        pinMode(LED_BUILTIN, OUTPUT);
        Serial.begin(115200);
        while(!Serial);
        Serial.println("\r\nInterrupt tester");
        Serial.print(NVIC_NUM_INTERRUPTS, DEC);
        Serial.println(" Interrupts available.");

#if defined(CORE_TEENSY)
        unsigned char n = 0;  
        while (swInterrupts[n] > 0) {
                int interrupt = swInterrupts[n];
                _VectorsRam[interrupt+16] = (uint32_t)softISR;
                NVIC_ENABLE_IRQ(interrupt);    
                n++;
        }
#else
        uint32_t *X_Vectors = (uint32_t *)((uint32_t)SCB->VTOR);
        for(int i = 0; i < VECTORTABLE_SIZE; i++) {
                _VectorsRam[i] = X_Vectors[i]; /* copy vector table to RAM */
        }
        /* relocate vector table */
        __disable_irq();
        SCB->VTOR = (uint32_t) & _VectorsRam;
        __DSB();
        __enable_irq();
        for(int interrupt=0; interrupt<NVIC_NUM_INTERRUPTS; interrupt++) {
                _VectorsRam[interrupt+16] = (uint32_t)softISR;
                NVIC_ENABLE_IRQ(interrupt);    
        }
#endif        
}

void loop() {    
#if defined(CORE_TEENSY)
        unsigned char n = 0;  
        while (swInterrupts[n] > 0) {    
                int interrupt = swInterrupts[n];
                Serial.print(interrupt + 16);
                Serial.print(" (");
                Serial.print(interrupt);
                Serial.print(")");
                chk = 0;
                NVIC_SET_PENDING(interrupt);
                delay(500);
                if (!chk) Serial.println("...NOT OK.");
                n++;
        }
#else
        for(int interrupt=0; interrupt<PERIPH_COUNT_IRQn; interrupt++) {
                Serial.print(interrupt + 16);
                Serial.print(" (");
                Serial.print(interrupt);
                Serial.print(")");
                chk = 0;
                NVIC_SET_PENDING(interrupt);
                delay(500);
                if (!chk) Serial.println("...NOT OK.");
        }
#endif
        Serial.println("Done.");
        while(1){;}
}

If anyone owns an Arduino Due, I'd be highly interested to know if the code works, as that would verify that my CMSIS porting is indeed MCU and board vendor agnostic.
 
One other point... I found out how to trip that ld bug. prototype the function in the header as extern "C" ... then don't extern "C" in the cpp code. that causes ld to totally spaz.
So, it is a real bug. and I have identified it.
 
I'm trying to understand the state of USB host mode and when it might be possible to do things like connect typical USB devices to a Teensy 3 such as a USB keyboard, flash memory stick, wifi dongle, etc.

If I understand xxajk correctly, he's very close to having USB Host mode support (without an additional circuit board), but he's waiting on a couple of tweaks to the current usb mode/boards.txt support to allow a "none" mode.

There's also work going on by Pedvide but it is in a nascent state. At least a couple of others have indicated interest in working on the problem.

As of now, the practical alternatives I'm aware of are either to use the Circuits@Home USB Host Shield for Arduino Pro Mini or to use alternate interfaces such as serial, I2C, SPI, etc.
 
I'm trying to understand the state of USB host mode and when it might be possible to do things like connect typical USB devices to a Teensy 3 such as a USB keyboard, flash memory stick, wifi dongle, etc.
Exactly, and more than one device when you attach a hub.
If I understand xxajk correctly, he's very close to having USB Host mode support (without an additional circuit board), but he's waiting on a couple of tweaks to the current usb mode/boards.txt support to allow a "none" mode.
Partially. "None" mode would allow for custom device mode. Another option, 'host' mode would allow host. There should be an 'OTG' mode also, to allow switching. All three would be nearly the same, but not quite.
There's also work going on by Pedvide but it is in a nascent state. At least a couple of others have indicated interest in working on the problem.
I'll have to take a look at that and see if I can gleen anything useful from it.
As of now, the practical alternatives I'm aware of are either to use the Circuits@Home USB Host Shield for Arduino Pro Mini or to use alternate interfaces such as serial, I2C, SPI, etc.
Yes, and the initial development is using the UHS mini. One thing I know that Paul is going to have to be convinced of is using malloc in an ISR. It is totally safe though once the additional library bits are added.
To this day I still ponder why nobody likes the idea of making libc's heap management ISR safe. RTOS's do this via wrappers anyway. :rolleyes:
I just eliminate the middle man and the wrapper. The nice thing is that the libc already supports the hook. I don't personally see a problem with a little bitty delay of an ISR someplace. Right now it is a global deal. The heap calls are so infrequently used outside of an ISR to begin with that the impact should be minimal anyway.

One idea could be to do like SPI, and register ISRs that use heap? Perhaps... but not at the moment. My bet is that if it were done this way, others may have less of an issue with it.
 
@pictographer:
Pedvide has been added to our development team.
Thanks a lot for pointing out someone with similar goals.
 
A little function that is handy sometimes:

Code:
//(c) Frank B 2017/4
//License: MIT

void listInterrupts() {
  unsigned adrFaultNMI = (unsigned)_VectorsRam[3];
  unsigned adrUnusedInt = (unsigned)_VectorsRam[IRQ_FTFL_COLLISION + 16];//IRQ_FTFL_COLLISION is normally unused
  unsigned adr;

  Serial.println("Interrupts in use:");
  Serial.println("NMI (non-maskable):");
  for (unsigned i = 1; i < 16; i++) {
    adr = (unsigned)_VectorsRam[i];
    if (adr != adrUnusedInt) {
      Serial.print(i);
      Serial.print(": \t");
      if (adr == adrFaultNMI) {
        Serial.print("Fault NMI");
      } else {
        Serial.print("\t");
      }      
      Serial.print("\t0x");
      Serial.print(adr, HEX);      
      Serial.println();
    }
     
  }
  Serial.println("IRQ:");
  for (unsigned i = 0; i < NVIC_NUM_INTERRUPTS; i++) {
    adr = (unsigned)_VectorsRam[i + 16];
    if (adr != adrUnusedInt) {
      Serial.print(i);
      Serial.print(": ");
      Serial.print("\tPriority:");
      Serial.print(NVIC_GET_PRIORITY(i));
      Serial.print("\t0x");
      Serial.print(adr, HEX);      
      if (NVIC_IS_ENABLED(i)) Serial.print("\t is enabled");
      Serial.println();
    }
  }
}

void setup() {
  Serial.begin(9600);
  //Serial1.begin(9600);
  listInterrupts();
}

void loop() {
}

Output is as follows (T3.6 here):
Code:
Interrupts in use:
NMI (non-maskable):
1:                   0x411
3:      Fault NMI    0xB31
4:      Fault NMI    0xB31
5:      Fault NMI    0xB31
6:      Fault NMI    0xB31
7:      Fault NMI    0xB31
8:      Fault NMI    0xB31
9:      Fault NMI    0xB31
10:     Fault NMI    0xB31
13:     Fault NMI    0xB31
15:                  0x196D
IRQ:
31:     Priority:64     0xA1D     is enabled
33:     Priority:128    0x90D
35:     Priority:128    0x831
37:     Priority:128    0x759
53:     Priority:112    0x1D8D     is enabled
66:     Priority:128    0x681
86:     Priority:128    0x19A5
Maybe it's useful for others, too.
To stay on topic: All other interrupts can be used as "Software Interrupt".
 
Thanks Frank,

Nice program that could come in handy. Would be useful to tag it in the hopefully someday Wiki or as an example program.
 
Back
Top