0
\$\begingroup\$

TLDR ATmega4809, mis-labelled ISR in iom4809.h. How can I define an ISR without using these mis-labelled predefined values from iom4809?

Using the ATmega4809 Xplained Pro eval board, I'm setting up asynchronous USART transmission, using the data register empty interrupt to always send the next available byte. If there are no more bytes to send, I disable the interrupt. I'm using the example USART project from MicroChip, directly from the Atmel Studio project generator.

/* Interrupt service routine for Data Register Empty */
ISR(USART1_DRE_vect)
{
     // I need to handle this interrupt.
} 


int8_t USART_0_init()
{

    USART1.BAUD = (uint16_t)USART1_BAUD_RATE(9600); /* set baud rate register */

    USART1.CTRLA = 0 << USART_ABEIE_bp    /* Auto-baud Error Interrupt Enable: disabled */
                   | 0 << USART_DREIE_bp  /* Data Register Empty Interrupt Enable: disabled */
                   | 0 << USART_LBME_bp   /* Loop-back Mode Enable: disabled */
                   | USART_RS485_OFF_gc   /* RS485 Mode disabled */
                   | 0 << USART_RXCIE_bp  /* Receive Complete Interrupt Enable: enabled */
                   | 0 << USART_RXSIE_bp  /* Receiver Start Frame Interrupt Enable: disabled */
                   | 0 << USART_TXCIE_bp; /* Transmit Complete Interrupt Enable: disabled */

    USART1.CTRLB = 0 << USART_MPCM_bp       /* Multi-processor Communication Mode: disabled */
                   | 0 << USART_ODME_bp     /* Open Drain Mode Enable: disabled */
                   | 0 << USART_RXEN_bp     /* Reciever enable: disabled */
                   | USART_RXMODE_NORMAL_gc /* Normal mode */
                   | 0 << USART_SFDEN_bp    /* Start Frame Detection Enable: disabled */
                   | 1 << USART_TXEN_bp;    /* Transmitter Enable: enabled */

    USART1.CTRLC = USART_CMODE_ASYNCHRONOUS_gc /* Asynchronous Mode */
             | USART_CHSIZE_8BIT_gc /* Character size: 8 bit */
             | USART_PMODE_DISABLED_gc /* No Parity */
             | USART_SBMODE_1BIT_gc; /* 1 stop bit */
}

No matter what I tried, I couldn't seem to get the data register empty interrupt to fire. I figured out that there was an inconsistency between the datasheet and the library that defines the interrupt vector.

From the 4809 datasheet:

26 0x1A 0x34 USART1 - Receive Complete

27 0x1B 0x36 USART1 - Data Register Empty

28 0x1C 0x38 USART1 - Transmit Complete

From iom4809.h

This doesn't match!! It is interrupt number 27 in data sheet and interrupt number 26 in the iom4809 library.

#define USART1_DRE_vect_num  26
#define USART1_DRE_vect      _VECTOR(26)
#define USART1_RXC_vect_num  27
#define USART1_RXC_vect      _VECTOR(27)
#define USART1_TXC_vect_num  28
#define USART1_TXC_vect      _VECTOR(28)

How can I define an ISR without using these mis-labelled predefined values from iom4809?

\$\endgroup\$
2
\$\begingroup\$

Update: There is a device pack in Atmel Studio to fix the iom4809.h library.

Please update ATmega DFP from the pack manager available from Studio: Tools -> Device Pack Manager.

In case if you get any time out error while installing the packs from Studio: Tools -> Device Pack Manager, device packs can be directly downloaded from http://packs.download.atmel.com/

Once the required pack is downloaded, double click the atpack file to open and install the same.


The only thing those macros do is define a vector location from a number through _VECTOR().

You can do it "quick-hack" style, by just inserting _VECTOR(27) in your ISR and label it as /* This is a hotfix, as the DRE vector is mis-labled in the ASF library, 27 is DRE. */.

That would be considered "Magic Number Coding", which is essentially a bad practise, but for a quick test it's an option.

But, you can also make it more intelligent and clean, you can undefine a constant using #undef.

You can also check values with #if.

To start simple, you could write:

#if (USART1_DRE_vect_num == 26)
  #undef USART1_DRE_vect
  #undef USART1_DRE_vect_num
  #define USART1_DRE_vect_num    27
  #define USART1_DRE_vect        _VECTOR(27)
#endif

And you can even, to make it cleaner add a device-type check around it, there's a lot of examples of that in the libraries themselves. I think Atmel Studio uses the "DEVICE" or "TARGET" identifier for that by default, but I'm not at my dev lab, so can't check right now.

Then you can just make a whole "Clean-Up" header for all the mistakes that checks if they still exist in the library. Maybe you can also add a line like:

#warning "Overrode a default Atmel identifier as they do not conform to the datasheet"

Then if after an update the warnings disappear, you know you can disable your header.

Make sure you include an over-ride header last, else your definition may not be triggered, since an undefined variable doesn't trigger the "== 26".

In fact, technically you should add defined(USART1_DRE_vect_num) to your #if clause to check for that yourself, to make your code universally compatible. But then, you probably want to check more extensively and add more warnings or errors, because in that case something will go wrong down the line anyway.

If you do NOT care at all about your project's portability to any other computers, you could also edit the header file itself, but I'd strongly suggest you try to avoid that as a matter of standard practise.


Last note: I have a gut feeling someone at some point in the future is going to say something incomprehensibly stupid like "Just use the vector with the right number". Which creates badly documented code at the very least and is dangerous. Your code will read as if you are doing something very silly on a completely different named interrupt. (And will stop working when they fix the bug)

Oh, and, file a bug report!

To summarize the "workaround" until MicroChip fixes the library:

#if (defined(USART1_DRE_vect_num) && USART1_DRE_vect_num == 26)
    #warning "Overrode a default Atmel identifier as they do not conform to the datasheet"
    #undef USART1_DRE_vect
    #undef USART1_DRE_vect_num
    #undef USART1_RXC_vect
    #undef USART1_RXC_vect_num
    // Redefine to vector numbers to match the ATmega4809 datasheet
    #define USART1_DRE_vect_num    27
    #define USART1_DRE_vect        _VECTOR(27)
    #define USART1_RXC_vect_num    26
    #define USART1_RXC_vect        _VECTOR(26)
#endif
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Excellent. I'll give this a try shortly and file a bug report. \$\endgroup\$ – Scampbell May 3 '18 at 20:22
  • \$\begingroup\$ Either using "ISR(__VECTOR(27)) {}" or "#define X __VECTOR27", I get an error "redefinition of '__vector_27'". Any ideas why that might be? \$\endgroup\$ – Scampbell May 3 '18 at 20:58
  • \$\begingroup\$ Nevermind, that redefinition error was because I also had to #undef the current vector 27 and change it to 26. I've submitted a support ticket with microchip so they can sort it out. Thanks! \$\endgroup\$ – Scampbell May 3 '18 at 21:18
  • \$\begingroup\$ Microchip support confirmed this was a bug in the iom4809.h library file and have passed it onto the right team there. \$\endgroup\$ – Scampbell May 7 '18 at 17:12
  • \$\begingroup\$ @Scampbell good to hear they at least still take it as seriously as they used to... though the current SW revision is October... frown Also, I accept your added summary ;-) (ask people in chat, it's a compliment :-P ) \$\endgroup\$ – Asmyldof May 8 '18 at 22:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.