EmbeddedRelated.com
Forums

Problem with register IE1 (UART TX problem)

Started by iirojan January 16, 2006
Hi!

I have a problem with UART0 output to my computer (only TX). The MCU I
am using is MSP430F169 and I initialize the UART with the code at the
end of the message. I use IAR V3.30A for compiling and debugging
(company policy).

UART0 works fine for a while, until something like 160-170 characters
have been outputted. I have a circular buffer to supply for
characters. The buffer setup has worked perfectly in my previous
MSP430 devices (for the exact same purpose). It seems not that the
buffer causes trouble, as spying the variables reveals nothing special
there, but what worries me is thate I find the register IE1 to have
changed when the UART output ceases:

IE1 == 0x01     (i.e. IE1 == WDTIE)

which means that IE1 & UTXIE0 == 0. No surprise that UTX output has
stopped.

So if I understand the situation correctly, something has changed the
IE1 register and the UART TX is not active anymore. What could do
that? I find nothing of the kind in the code, so this should be
something processor internal. Searching the MSP430x1xx Family User's
Guide doesn't reveal anything for me about this subject.

Thanks in advance for any advice.

 -- Iiro Jantunen 

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 

void uart0_init(void)
{
  _DINT();	  // disable interrupts

  U0CTL |= SWRST; // set SWRST first to make sure USART is off

  // set the baud rate to 115 200
  UBR00 = 0x45;
  UBR10 = 0x00;
  UMCTL0 = 0x00;

  // the UART mode
  U0CTL &= SWRST; // unset all else than SWRST
  U0CTL |= CHAR;  // USART Control Register
                  // Use 8-bit data, 1 stop bit, no parity check
  U0TCTL = SSEL0+SSEL1; // Transmit Control Register
                  // Use SMCLK for baud-rate generation

  ME1 |= UTXE0;   // Enable UART0 transmit (Module Enable 1)

  U0CTL &= ~SWRST;// clear SWRST

  IE1 |= UTXIE0;  // Enable UART0 tx interrupts (Interrupt Enable 1)

  IFG1 |= UTXIFG0;// USART transmitter ready (Interrupt Flag Register 1)
  P3DIR |= BIT4;  // Use P3.4 as TX for USART0-module (output)
  P3SEL |= BIT4;

  _EINT();	          // enable interrupts
}

char uart0_putchar(unsigned char c)
{
  u16 in; // holds temporary the new transmit 
  in = uart0_tx_wr + 1;     
     // calculate the new transmitt write pointer value	
  if (in >= UART0_BUF_SIZE) 
     // check if the buffer size is exceeded
    in = 0; 
    // buffer size exceeded -> put the pointer to the start of the
buffer		
  
  if (in == uart0_tx_rd)    
  // check if the new transmit write pointer is the same as the transmit
  // read pointer which would mean that the buffer is full
    return 0;               // buffer is full
  else                      // buffer is not full
  {
    uart0_tx_buffer[uart0_tx_wr] = c; // put character into buffer
    _DINT();                          // disable interrupts
    if (uart0_tx_off)                 // check if no sending is in process
    {
      uart0_tx_rd = in;     // set transmit read pointer
      uart0_tx_off = 0;     // set the flag, that sending is in process
      U0TXBUF = c;          // send the character -> send interrupt is
triggered
    }
    uart0_tx_wr = in; 	    // update transmit write pointer
    _EINT();                // enable interrupts
  }
  return 1;                 // sending successful
}







Beginning Microcontrollers with the MSP430

Iiro,

These registers are low in memory - a write to a NULL pointer can cause 
this - if you "run out of memory" - anything that
can cause a pointer to be 0x0000 - will cause this to happen.  You can put 
breakpoints on these values to monitor.  This is
a 'weakness' in the MSP430 architecture and tools in my opinion. 
Important 
system level registers should not be located
beginning at address 0x0000 - at least not in my opinion.  I think this is 
what is happening to you.

Regards,
John W.

----- Original Message ----- 
From: "iirojan" <iiro.jantunen@iiro...>
To: <msp430@msp4...>
Sent: Monday, January 16, 2006 12:51 AM
Subject: [msp430] Problem with register IE1 (UART TX problem)


> Hi!
>
> I have a problem with UART0 output to my computer (only TX). The MCU I
> am using is MSP430F169 and I initialize the UART with the code at the
> end of the message. I use IAR V3.30A for compiling and debugging
> (company policy).
>
> UART0 works fine for a while, until something like 160-170 characters
> have been outputted. I have a circular buffer to supply for
> characters. The buffer setup has worked perfectly in my previous
> MSP430 devices (for the exact same purpose). It seems not that the
> buffer causes trouble, as spying the variables reveals nothing special
> there, but what worries me is thate I find the register IE1 to have
> changed when the UART output ceases:
>
> IE1 == 0x01     (i.e. IE1 == WDTIE)
>
> which means that IE1 & UTXIE0 == 0. No surprise that UTX output has
> stopped.
>
> So if I understand the situation correctly, something has changed the
> IE1 register and the UART TX is not active anymore. What could do
> that? I find nothing of the kind in the code, so this should be
> something processor internal. Searching the MSP430x1xx Family User's
> Guide doesn't reveal anything for me about this subject.
>
> Thanks in advance for any advice.
>
> -- Iiro Jantunen
>
> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
>
> void uart0_init(void)
> {
>  _DINT();   // disable interrupts
>
>  U0CTL |= SWRST; // set SWRST first to make sure USART is off
>
>  // set the baud rate to 115 200
>  UBR00 = 0x45;
>  UBR10 = 0x00;
>  UMCTL0 = 0x00;
>
>  // the UART mode
>  U0CTL &= SWRST; // unset all else than SWRST
>  U0CTL |= CHAR;  // USART Control Register
>                  // Use 8-bit data, 1 stop bit, no parity check
>  U0TCTL = SSEL0+SSEL1; // Transmit Control Register
>                  // Use SMCLK for baud-rate generation
>
>  ME1 |= UTXE0;   // Enable UART0 transmit (Module Enable 1)
>
>  U0CTL &= ~SWRST;// clear SWRST
>
>  IE1 |= UTXIE0;  // Enable UART0 tx interrupts (Interrupt Enable 1)
>
>  IFG1 |= UTXIFG0;// USART transmitter ready (Interrupt Flag Register 1)
>  P3DIR |= BIT4;  // Use P3.4 as TX for USART0-module (output)
>  P3SEL |= BIT4;
>
>  _EINT();           // enable interrupts
> }
>
> char uart0_putchar(unsigned char c)
> {
>  u16 in; // holds temporary the new transmit
>  in = uart0_tx_wr + 1;
>     // calculate the new transmitt write pointer value
>  if (in >= UART0_BUF_SIZE)
>     // check if the buffer size is exceeded
>    in = 0;
>    // buffer size exceeded -> put the pointer to the start of the
> buffer
>
>  if (in == uart0_tx_rd)
>  // check if the new transmit write pointer is the same as the transmit
>  // read pointer which would mean that the buffer is full
>    return 0;               // buffer is full
>  else                      // buffer is not full
>  {
>    uart0_tx_buffer[uart0_tx_wr] = c; // put character into buffer
>    _DINT();                          // disable interrupts
>    if (uart0_tx_off)                 // check if no sending is in process
>    {
>      uart0_tx_rd = in;     // set transmit read pointer
>      uart0_tx_off = 0;     // set the flag, that sending is in process
>      U0TXBUF = c;          // send the character -> send interrupt is
> triggered
>    }
>    uart0_tx_wr = in;     // update transmit write pointer
>    _EINT();                // enable interrupts
>  }
>  return 1;                 // sending successful
> }
>
>
>
>
>
>
>
>
> .
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
> 



Perhaps it should also be annunciated that you should NEVER write to a VOID
*.
(including a NULL of course).
A void pointer could be holding any address, including 0, so personally I
wouldn't hold that
against the MSP430, it's a violation of C.

B rgds
Kris

-----Original Message-----
From: msp430@msp4... [mailto:msp430@msp4...] On Behalf Of John C. Westmoreland,
P.E.
Sent: Tuesday, 17 January 2006 5:12 PM
To: msp430@msp4...
Subject: Re: [msp430] Problem with register IE1 (UART TX problem)

Iiro,

These registers are low in memory - a write to a NULL pointer can cause 
this - if you "run out of memory" - anything that
can cause a pointer to be 0x0000 - will cause this to happen.  You can put 
breakpoints on these values to monitor.  This is
a 'weakness' in the MSP430 architecture and tools in my opinion. 
Important 
system level registers should not be located
beginning at address 0x0000 - at least not in my opinion.  I think this is 
what is happening to you.

Regards,
John W.

----- Original Message ----- 
From: "iirojan" <iiro.jantunen@iiro...>
To: <msp430@msp4...>
Sent: Monday, January 16, 2006 12:51 AM
Subject: [msp430] Problem with register IE1 (UART TX problem)


> Hi!
>
> I have a problem with UART0 output to my computer (only TX). The MCU I
> am using is MSP430F169 and I initialize the UART with the code at the
> end of the message. I use IAR V3.30A for compiling and debugging
> (company policy).
>
> UART0 works fine for a while, until something like 160-170 characters
> have been outputted. I have a circular buffer to supply for
> characters. The buffer setup has worked perfectly in my previous
> MSP430 devices (for the exact same purpose). It seems not that the
> buffer causes trouble, as spying the variables reveals nothing special
> there, but what worries me is thate I find the register IE1 to have
> changed when the UART output ceases:
>
> IE1 == 0x01     (i.e. IE1 == WDTIE)
>
> which means that IE1 & UTXIE0 == 0. No surprise that UTX output has
> stopped.
>
> So if I understand the situation correctly, something has changed the
> IE1 register and the UART TX is not active anymore. What could do
> that? I find nothing of the kind in the code, so this should be
> something processor internal. Searching the MSP430x1xx Family User's
> Guide doesn't reveal anything for me about this subject.
>
> Thanks in advance for any advice.
>
> -- Iiro Jantunen
>
> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
>
> void uart0_init(void)
> {
>  _DINT();   // disable interrupts
>
>  U0CTL |= SWRST; // set SWRST first to make sure USART is off
>
>  // set the baud rate to 115 200
>  UBR00 = 0x45;
>  UBR10 = 0x00;
>  UMCTL0 = 0x00;
>
>  // the UART mode
>  U0CTL &= SWRST; // unset all else than SWRST
>  U0CTL |= CHAR;  // USART Control Register
>                  // Use 8-bit data, 1 stop bit, no parity check
>  U0TCTL = SSEL0+SSEL1; // Transmit Control Register
>                  // Use SMCLK for baud-rate generation
>
>  ME1 |= UTXE0;   // Enable UART0 transmit (Module Enable 1)
>
>  U0CTL &= ~SWRST;// clear SWRST
>
>  IE1 |= UTXIE0;  // Enable UART0 tx interrupts (Interrupt Enable 1)
>
>  IFG1 |= UTXIFG0;// USART transmitter ready (Interrupt Flag Register 1)
>  P3DIR |= BIT4;  // Use P3.4 as TX for USART0-module (output)
>  P3SEL |= BIT4;
>
>  _EINT();           // enable interrupts
> }
>
> char uart0_putchar(unsigned char c)
> {
>  u16 in; // holds temporary the new transmit
>  in = uart0_tx_wr + 1;
>     // calculate the new transmitt write pointer value
>  if (in >= UART0_BUF_SIZE)
>     // check if the buffer size is exceeded
>    in = 0;
>    // buffer size exceeded -> put the pointer to the start of the
> buffer
>
>  if (in == uart0_tx_rd)
>  // check if the new transmit write pointer is the same as the transmit
>  // read pointer which would mean that the buffer is full
>    return 0;               // buffer is full
>  else                      // buffer is not full
>  {
>    uart0_tx_buffer[uart0_tx_wr] = c; // put character into buffer
>    _DINT();                          // disable interrupts
>    if (uart0_tx_off)                 // check if no sending is in process
>    {
>      uart0_tx_rd = in;     // set transmit read pointer
>      uart0_tx_off = 0;     // set the flag, that sending is in process
>      U0TXBUF = c;          // send the character -> send interrupt is
> triggered
>    }
>    uart0_tx_wr = in;     // update transmit write pointer
>    _EINT();                // enable interrupts
>  }
>  return 1;                 // sending successful
> }
>
>
>
>
>
>
>
>
> .
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
> 




.

 
Yahoo! Groups Links



 





"John C. Westmoreland, P.E." <john@w...> wrote:
> These registers are low in memory - a write to a
NULL pointer can cause 
> this - if you "run out of memory" - anything that
> can cause a pointer to be 0x0000 - will cause this to happen.  You
can put 
> breakpoints on these values to monitor. This is
> a 'weakness' in the MSP430 architecture and tools in my opinion. 
Important 
> system level registers should not be located
> beginning at address 0x0000 - at least not in my opinion.  I think
this is 
> what is happening to you.

Propably this is exactly what is happening to me. I'm reimplementing a
code contributed by a project partner to my company a few years ago.
The code implements nanoIP, with a radio interface. The code is poorly
written, virtually uncommented, and plagued by difficult to resolve
errors. The code is particularly poor about pointers, with a few clear
errors like (ri stands for radio interface):

uint8_t *ri_count;                 // [1] global variable

ri_count++;                        // [2] 
ri_count = responses;              // [3] uint8_t *responses
ri_count = 0;                      // [4] 
if ((uint8_t) ri_count == 1)       // [5] 
if (*ri_count < ri_limit)          // [6] 
response = &(response[*ri_count]); // [7] 
*ri_count = *ri_count + 1;         // [8] 

[4] and [5] can not be right, that's for sure. But is [2] right? By
syntax yes, but neither I or the writer of the code (who has long
forgotten this project) can be sure is it good for the functionality
without an extensive analysis of the code as a whole.

So, propably I have not found all the errors in the code yet. Thanks
for the good hint, I'll try to find the remaining errors.

-- 
Iiro Jantunen






iirojan wrote:
> Propably this is exactly what is happening to me.
I'm reimplementing a
> code contributed by a project partner to my company a few years ago.

Good idea to rewrite it, line for line, using clean
and type-correct code. You'll find pretty-much all
the errors without having to do much design (assuming
it all worked once). It's much quicker to rewrite
things that you might think.

> The code is particularly poor about pointers, with
a few clear
> errors like (ri stands for radio interface):
> uint8_t *ri_count;                 // [1] global variable

No problem there, ri_count points at a uint8_t (presumable a byte)

> ri_count++;                        // [2] 

Ok, point to the next byte - no drama.

> ri_count = responses;              // [3] uint8_t
*responses

point to the same thing that "responses" points to.

> ri_count = 0;                      // [4] 

No problem here, you're just nullifying the pointer.

> if ((uint8_t) ri_count == 1)       // [5] 

Hmm, that's not good, using the pointer as an integer.

> if (*ri_count < ri_limit)          // [6] 

if "ri_limit" is a uint8_t, that's fine, as long as
ri_count isn't null.

> response = &(response[*ri_count]); // [7] 

This is the same as response += *ri_count;
which could be valid, if the value of *ri_count
has been checked and won't make response point
somewhere illegal.

> *ri_count = *ri_count + 1;         // [8]

Same as *ri_count++, quite legal.

> [4] and [5] can not be right, that's for
sure.

It's possible that the code is ok(-ish) and it's mainly
your understanding of C that's flawed. But without the
context, I couldn't say.  A lot of communications code
is wrapping and unwrapping strings of bytes in envelope
headers that can be represented by structures. A mistake
that beginners make is not to declare structures for the
headers, preferring to pack bytes manually instead.

Clifford Heath.

"iirojan" <iiro.jantunen@h...> wrote:
> ri_count = 0;                      // [4] 

OK. Found the problem. Here the pointer ri_count points to memory
address 0 which seems to be IE1. At least this declaration zeroes the IE1.

The trouble seems to be the fact that the original code does not
initialize the "uint8_t *ri_count" at all.

As the ri_count is an global pointer variable, I have trouble
understanding a correct way to initialize it. What is the correct way
(all in global variables)? 

char variableA = 0;  // initializes nicely

char variableA; // initializes nicely, only does not have a value

char *variableA; // does not initialize at all

char *variableA = malloc(sizeof(char)*10); // does not compile

Of course I could initialize it in init() function, but is it the
correct way?

char *variableA;

void init() {
  variableA = malloc(sizeof(char)*10);
}

So what should I do?

-- 
Iiro Jantunen




Clifford Heath <cjh@m...> wrote:
> Good idea to rewrite it, line for line, using
clean
> and type-correct code. You'll find pretty-much all
> the errors without having to do much design (assuming
> it all worked once). It's much quicker to rewrite
> things that you might think.

Not a very good idea, as far as I found out. The code was "ready to
use" as I was told and I was not allocated time to work with it. The
code, nanoIP, is quite a complex pile of spaghetti, and I have never
before written code for communications software. It has taken an
eternity, and I still do not understand most of the logic, ridden with
sockets, handlers and interrupts. The functionality of the code,
including SPI link to a FPGA, is strictly defined - so I have little
possibility to change the structure of the code without complete
understanding what I am doing.

The code was also written to be used in both MSP430 and AVR
microcontrollers and the interoperability was avhieved by using a mess
of #ifdef MSP430 ... #ifdef AVR and a few other preprocessor
variables. The resulting code was poorly debuggable by Doxygen,
because it has little chance of understanding the ifdef mess (should
functionA() refer to the definition inside #ifdef MSP430 or #ifdef AVR
or other).

What I am writing is an sensor server on MSP430, so that (as OSI model
states) the layer structure inside the microcontroller is about as
follows:

SSI (Simple Sensor Interface protocol, see http://ssi-protocol.net)
nanoUDP/nanoIP (see http://www.cwc.oulu.fi/nanoip/)
radio_interface/upper layer interface
SPI
...

Thanks for all the hints and suggestions, though.

-- 
Iiro Jantunen




> ...The code was "ready to use"
> ...The code, nanoIP, is quite a complex pile of
spaghetti,

These facts are contradictory. Which one is true?

> and I have never before written code for
communications software.

Then even if nanoIP was ready to use, you're not ready to use it.

> ...a mess of #ifdef MSP430 ... #ifdef AVR and a
few other preprocessor

So get a copy of scpp and remove all the AVR ifdefs. I'd leave
the MSP430 ones though, so you can tell where there are device
dependencies.

> > ri_count = 0;                      // [4] 
> OK. Found the problem. Here the pointer ri_count points to memory
> address 0 which seems to be IE1. At least this declaration zeroes the
IE1.

No it doesn't. It zeroes the pointer. You'd need then to say
*ri_count = 0;
to zero IE1.

A book on C would help also. All your global variables are
initialised, whether you declare values for them or not.
This is defined by the C language, and if you don't know it,
I don't like your chances.

Hi,

> The code was also written to be used in both
MSP430 and AVR
> microcontrollers and the interoperability was avhieved by using a mess
> of #ifdef MSP430 ... #ifdef AVR and a few other preprocessor
> variables. The resulting code was poorly debuggable by Doxygen,
> because it has little chance of understanding the ifdef mess (should
> functionA() refer to the definition inside #ifdef MSP430 or #ifdef AVR
> or other).

You can provide preprocess symbols to Doxygen.
If you use the WIN GUI, it's one of the options in "Advanced".

B rgds
Kris


"Clifford Heath" <cjh@m...> wrote:
> > ...The code was "ready to use"
> > ...The code, nanoIP, is quite a complex pile of spaghetti,
> 
> These facts are contradictory. Which one is true?

Both. "Ready to use" meaned that the code worked in another emebedded
system setup, on the same type of processor and quite similar
architecture.

> > and I have never before written code for
communications software.
> 
> Then even if nanoIP was ready to use, you're not ready to use it.

Exactly. But I'm not here to discuss the distribution of work in my
project. Sufficient to say, communications sw layers should have been
work of some other people, but they just dumped me the nanoIP code
saying that it works in their device. They have been helping me to
sort out the mess, but the trouble is that they have not written the
code themselves, but or partner years ago - which means they could not
tell where the problem lies.

> So get a copy of scpp and remove all the AVR
ifdefs. I'd leave
> the MSP430 ones though, so you can tell where there are device
> dependencies.

I did it already, manually. Took time, though. The AVR and MSP430
ifdefs were not the only ifdefs... :(

> > > ri_count = 0;                      //
[4] 
> > OK. Found the problem. Here the pointer ri_count points to memory
> > address 0 which seems to be IE1. At least this declaration zeroes the
> IE1.
> 
> No it doesn't. It zeroes the pointer. You'd need then to say
> *ri_count = 0;
> to zero IE1.

Sorry about my erraneous copying. What was there, was "*ri_count = 0".
And that one zeroes the IE1. At least I saw that happening when
debugging single steps with IAR.

It must be frustrating to read this badly written posts. Sorry about
critical typing errors.

> A book on C would help also. All your global
variables are
> initialised, whether you declare values for them or not.
> This is defined by the C language, and if you don't know it,
> I don't like your chances.

I have studied and written C code. Just that I could not find any
reference (from the books I have) on what does a declaration like

char *pointerA;

in global variables exactly do? Where the pointer points to? How much
room is in the memory area pointed? I think that is not very
self-explaining as code.

Thanks for information!

-- 
Iiro Jantunen