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.

setting the USCI Interrupt enable

Part Number: MSP-EXP430F5529LP
Other Parts Discussed in Thread: MSP430F5529

OK - not sure whats going on here, trying to enable interrupts on a uart, done via USCI on MSP430F5529.

Code to set - and read out:

  HWREGB( USCI_A1_BASE | UCAxIE ) |= 0x03;
  *print=HWREGB( USCI_A1_BASE | UCAxIE )+'0';

where HWREGB is a macro to access bytes, at a memory location. The second line just moves to value to a print buffer thar offsets it by the '0' character. So I expect to see a '3' on the output. All I ever get is a '0'. Checked the assembler to make sure  its reasonable, and:

    45a0:       f2 d0 03 00     bis.b   #3,     &0x061c ;
    45a4:       1c 06 
    45a6:       5c 42 1c 06     mov.b   &0x061c,r12     ;0x061c
    45aa:       7c 50 30 00     add.b   #48,    r12     ;#0x0030

So thats all reasonable, right memory location for UCAxIE on USCI_A1_BASE on an msp430f5529; and its setting bits with 'bis' that much be the best method as the manual only says the first two bits are RW, the rest a R only.

But alas it doesn't seem to set those bits. So something strange going on. Anyone any ideas?

  • OK - *very* careful reading of the manual, and

    36.3.1 USCI Initialization and Reset
    The USCI is reset by a PUC or by setting the UCSWRST bit. After a PUC, the UCSWRST bit is
    automatically set, keeping the USCI in a reset condition. When set, the UCSWRST bit resets the UCRXIE,
    UCTXIE, UCRXIFG, UCRXERR, UCBRK, UCPE, UCOE, UCFE, UCSTOE, and UCBTOE bits, and sets
    the UCTXIFG bit. Clearing UCSWRST releases the USCI for operation.

    So I needed to write code in this order:

      // enable USCI A1
      HWREGB( USCI_A1_BASE | UCAxCTL1 ) &= ~UCSWRST;
      // interupts on both TX(2) and RX(1) UCTXIE and UCRXIE
      HWREGB( USCI_A1_BASE | UCAxIE ) |= 0x03;

    And enable the interrupts after enabling the UART (on USCI A1)

  • USCI_A1_BASE | UCAxIE may work here but is hazardous. When using a base address and an offset, you want addition, not a bit wise OR.

  • Hi David. Yes I know what you mean.

    I'm kinda in two minds myself. On the one hand these memory mapped external devices (to the main CPU) are usually mapped in a small window that is aligned. And this is generally a good approach when designing the chip, that TI tend to follow. Now there are exceptions, TIMER_B0_BASE has memory addresses that cross a page, e.g. TBxEX0 (0x20 + 0x3c0); so that case TBxEX0 has just moved into the next 32 byte window, so does the TIMER_B0 memory map span 64 bytes?

    To me, well I can see that for most cases "+" and "|" are equivalent; and both when compiled with constants - the compiler will do the operation; so no difference in code. Its kinda how you look at the operations "+" is arithmetic addition, "|" is logical addition. So with "BIT0 | BIT1" is more natural than "BIT0 + BIT1".

    So with a memory mapped device, with a base address, and offsets - how best is it looked at. Direction I went in, is most devices are memory mapped in a page or usually 32 bytes, so I want the operation to work by design on that page. And thats the "|" operation.

    So yes I know what you are saying, and yes am aware of the issue. Question though is what is best coding style, and for me, I'll still sucking air on that one. I can see both approach, just not sure which I like. Both have faults.

  • It requires deep knowledge of the details to know that a bitwise OR will work. But it is still a bad idea.

    I also have to wonder why do it this way when symbols like UCA1IE are available. The base and offset route is useful only if you are writing a driver which is used with all of the ports. Which one selected at runtime by passing it a pointer to the base address.

  • So you are saying that you consider that the memory address are offsets, so you always use "+".

    Me I was saying that memory mapped devices are memory aligned, and you should write to the memory aligned area.

    So to give an example from my msp430f5529, look at the memory addresses that occur in sequences:

    #define __MSP430_BASEADDRESS_PORT1_R__ 0x0200
    #define __MSP430_BASEADDRESS_PORT2_R__ 0x0200
    #define __MSP430_BASEADDRESS_PORTA_R__ 0x0200
    #define __MSP430_BASEADDRESS_PORT3_R__ 0x0220
    #define __MSP430_BASEADDRESS_PORT4_R__ 0x0220
    #define __MSP430_BASEADDRESS_PORTB_R__ 0x0220
    #define __MSP430_BASEADDRESS_PORT5_R__ 0x0240
    #define __MSP430_BASEADDRESS_PORT6_R__ 0x0240
    #define __MSP430_BASEADDRESS_PORTC_R__ 0x0240
    #define __MSP430_BASEADDRESS_PORT7_R__ 0x0260
    #define __MSP430_BASEADDRESS_PORT8_R__ 0x0260
    #define __MSP430_BASEADDRESS_PORTD_R__ 0x0260
    #define __MSP430_BASEADDRESS_PORTJ_R__ 0x0320
    #define __MSP430_BASEADDRESS_T0A5__ 0x0340
    #define __MSP430_BASEADDRESS_T1A3__ 0x0380
    #define __MSP430_BASEADDRESS_T2A3__ 0x0400
    #define __MSP430_BASEADDRESS_T0B7__ 0x03C0
    #define __MSP430_BASEADDRESS_USCI_A0__ 0x05C0
    #define __MSP430_BASEADDRESS_USCI_B0__ 0x05E0
    #define __MSP430_BASEADDRESS_USCI_A1__ 0x0600
    #define __MSP430_BASEADDRESS_USCI_B1__ 0x0620
    

    And you can see that the ports are aligned to 0x20, the Timers are aligned to 0x40, and the USCI devices are aligned to 0x20.

    Digital IO has max offset of 0x1f, Timers have max offset of 0x20, and USCI has a max offset of 0x1e.

    So each of the offsets like inside the window of each device.

    This is almost certainly by design on TI part, they design device memory address to be memory aligned.

    Then I guess it comes down to documentation, does anything in the documentation say that memory mapped devices are memory aligned.

    So consider your example UXAxIE has an offset value of 0x1c; it address USCI devices which are memory aligned to 0x20. So "|" works with this as USCI devices always have the lowest five bits set to zero, and all offsets are 5 bits long.

    I don't think there I have ever found a bit of code where "|" didn't work, Timer were the worst I saw, but their memory alignment has increased to 0x40.

    So you say "|" is unsafe, as for some addresses (not used by TI) it could give a wrong value from the english word "offset". I say "|" ensures the offset is always inside the memory alignment of the device, and so ensures you write to the memory of that device - so mine is safe.

    So when we say "safe" we have different meanings, you talk about "offset" in the english language is always a numerical addition. When I say "safe", I talk about the memory alignment of devices, so code should always write within the memory alignment of the device, so incorrect code can only mess up the device to which you are writing, and not some other device.

    I think we are just using different language here, but can we say one is definitely better coding style?  As I said earlier - its all a bit irrelevant, as good compiler will merge constants like this at compile time, and do that both for "+" and for "|". So code written either way will create the same assembly.

     

  • And just realised you meant literally UCA1IE rather than UCAxIE. Good question. To be honest I didn't realise it was defined, but see now it is. Quick look, so first thoughts.

    I was kind thinking that USCI_A1 is a memory mapped device, with a certain base address, and offsets with that address space. Its how the documentation is written. I then use code derived from the TIVA C line, to direct write to memory:

    #define HWREGB(x) (*((volatile uint8_t *)(x)))

    Where I kinda like the simplicity of it - that its writing 8 bits to memory.

    I like the base address and an offset, as in my mind I see the base address as referring to bit of hardware, and the offset referring to a register in that hardware, so for me it makes sense to reference both.

    Just trying to see how UCA1IE is defined in the header, haven't quite worked out the logic, looks like it is set up as an extern, and the linker then deals with it. This make some sense, but confuses me right now. I kinda like the code above, that just directly says, write to an address in memory - and this happens before the linker is invoked.

    Here is the TI reference btw https://software-dl.ti.com/simplelink/esd/simplelink_msp432e4_sdk/3.10.00.11/docs/driverlib/msp432e4/html/types_8h_source.html

    And worked out how UCA1IE is implemented:

    In: msp430f5529.h : #define UCA1IE                 UCA1ICTL_L     /* USCI A1 Interrupt Enable Register */
    In: msp430f5529_symbols.ld: PROVIDE(UCA1ICTL_L         = 0x061C);

    So it is unresolved in the c code, and the linker provides the missing reference. To my mind a bit of a confusing implementation - but that could just be me. And as far as I see, it just defines an address, and doesn't say the size of the data at address, e.g. the doesn't say if its a byte or a word.

    And I guess your solution would be

      HWREGB( UCA1IE ) |= BIT0|BIT1;

    And a bit more reading, and realise the standard msp430 coding would be

    UCA1IE |= BIT1|BIT0;
    and that can be compiled as just BIS instructions. But with
    UCA1IE=0x3;
    how does the compiler know it should write a unit8_t or unit16_t ? And even if the compilers knows (and I can't see how), this doesn't seem very transparent to me.

  • Hi David,

    Does your issue have been resolved?

    Thanks!

    Best Regards

    Johnson

  • Yes - the original problem was solved, you can only enable interrupts on the UCSI devices, after enabling the USCI device - so just had to make sure things were done in the right order.

    Thread then evolved into coding style for programming msp430 devices, thin David Schultz and I just have a slightly different style, so were discussing what to my mind is a fairly minor point.

    But anyway, yes original problem was solved - do things in the right order.

**Attention** This is a public forum