Jump to content
43oh

Simple Serial ( minimal ? ) debugging.


Recommended Posts

main.cpp

 

/** 
  A very basic implementation of hardware UART using oPossum's
  Tiny printf().
  Link: http://forum.43oh.com/topic/1289-tiny-printf-c-version/
  
  Code written by yyrkoon of forum.430h.com. To demonstrate
  UART, and printf() as a mechanism for Serial output used
  for debugging purposes.
  
  Following source is very trivial, common knowlege, and therefore
  open to public domain. 
  
**/
  
#include <msp430.h>
#include "uart.h"

void printf(char *, ...);                 // printf() output pointed to UART through putc()

int main(void) 
{
  WDTCTL = WDTPW + WDTHOLD;               // Disable watchdog.
  BCSCTL1 = CALBC1_1MHZ;                  // Load calibrated constants for 1Mhz operation.
  DCOCTL = CALDCO_1MHZ;                   // ...

  uart_initialize();                      // Initialize UART

  printf("Hello Launchpad v1.5 world \n\r");   

  return 0;
}

 

uart.h

 

#ifndef __UART_H
#define __UART_H

void uart_initialize(void);

#endif

 

uart.cpp

 

#include <msp430.h>

#define TXD  BIT2

void uart_initialize(void)
{
	P1SEL  = TXD;                       
  	P1SEL2 = TXD;                       
  	UCA0CTL1 |= UCSSEL_2;                     // SMCLK
  	UCA0BR0 = 104;                            // 1MHz 9600
  	UCA0BR1 = 0;                              // 1MHz 9600
  	UCA0MCTL = UCBRS0;                        // Modulation UCBRSx = 1
  	UCA0CTL1 &= ~UCSWRST;                     // Initialize USCI state machine
}

void putc(unsigned byte) 
{
	while (!(IFG2 & UCA0TXIFG));			
	UCA0TXBUF = byte;
}

void puts(char *str)
{
     while(*str) putc(*str++);
}

 

The source for oPossum's Tiny printf() must be downloaded separately on a user by user basis. Link provided in main.cpp. If you use / like his code, click the thanks button on his first post.

 

Once Tiny printf() is obtained, simply add it and the source above ( uart.h, and uart.cpp ) into your project. #include uart.h in main cpp. Then finally make sure the printf() prototype is declared just above main. As shown in main.cpp. 

 

This source was compiled using Energia, with the Energia framework bypassed( gcc-msp430.). It works as intended.

 

RX /TX jumpers on the launchpad should probably be set into hardware configuration.

 

 

Binary sketch size: 711 bytes (of a 16,384 byte maximum).
 
I do have plans on reducing code size on target in the future, but for now this is how the code stands. I just needed a simple method to debug code, since Energia's Serial.print() methods require too much memory for my own taste.
 
Anyway, maybe this will help others as well.
 
Link to post
Share on other sites

Yes, I was looking at your post, and oPossum's for same related material. It bothers me to hard code things like this, *but* this keeps it simple, and short.

 

However, what does your ASM debugger have to do with being simple ?   oPossum already wrote assembly source for printf() to use uart output mentioned on the Tiny printf() page.

 

What I have here, is meant more as beginner learning code, that just so happens to provide some useful functionality.

Link to post
Share on other sites
  • 4 weeks later...

Here is yet another text only implementation. However, you can use itoa() to convert integers to string format, which in return can then be printed. This does however add some overhead, but is the smallest I have yet tested. Using oPossums Tiny printf() may even yield smaller results.

 

With the above said, with the G2553 MSP430's "tiny" is not necessarily needed, but is a good exercise in learning how to reduce code size as much as possible ( for when it *is* needed ).

 

Inspired by Rickta59's Serial / UART code in Energia. In fact, the Initialization code is nearly all his. This is a C++ template class implementation however.

 

Code size on target.

Writing  186 bytes at c000...
Writing   32 bytes at ffe0...
Done, 218 bytes total

 

 

hw_serial.h

namespace uart {

	template <uint32_t BAUD, uint32_t MCLK_HZ>
	struct UART
	{
		void Initialize(void);
		void Write(char ch);
		void Write(char *str);
		void Read(void);
	};

	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Initialize(void)
	{
		const uint32_t baud_rate_20_bit = (MCLK_HZ + (BAUD >> 1)) / BAUD;

		P1SEL |= BIT1 | BIT2;
		P1SEL2 |= BIT1 | BIT2;

		UCA0CTL1 = UCSWRST;                             
      	UCA0CTL0 = 0;                                   
      	UCA0BR1 = (baud_rate_20_bit >> 12) & 0xFF;    
      	UCA0BR0 = (baud_rate_20_bit >> 4) & 0xFF;      
      	UCA0MCTL = ((baud_rate_20_bit << 4) & 0xF0) | UCOS16; 
      	UCA0CTL1 = UCSSEL_2; 
	}

	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Write(char ch)
	{
		while(!(IFG2 & UCA0TXIFG));
		UCA0TXBUF = ch;
	}
	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Write(char *str)
	{
		while(*str) {
			Write(*str++);
		}
	}

} // end namespace

#include <msp430.h>
#include <stdint.h>
#include "hw_serial.h"

using namespace uart;

UART<9600, 1000000> Serial;

int main(void)
{

	WDTCTL = WDTPW | WDTHOLD;

  DCOCTL = 0;
  DCOCTL = CALDCO_1MHZ;
  BCSCTL1 = CALBC1_1MHZ;
  BCSCTL2 = DIVS_0;

  Serial.Initialize();

  Serial.Write("Hello World \r\n");

	return 0;
}

Link to post
Share on other sites

So the last example had no number printing capabilities, and was text only. I did some more testing last night, but with numbers. After fooling around with several different approaches ( including embedding opossums printf() code into my template class ). I settled for just adding a simple Write() overload which takes a value , and base parameter. Yes, that means with this code below, you can print any numerical value, with any base type that itoa() can take.

 

Granted, there are a few caveats here. such as there is no built in type checking really ( other than that which is provided by the compiler ), and there is no variable length checking / testing. This code as such implies that you the user of the code knows what you're doing. If you really want to break it, then it should not be too hard. If you use it correctly though, it so far is the smallest / most efficient way I have tested up to this point. Granted with C, or ASM you may be able to write code that is slightly smaller, but I am pretty sure at this point I am bumping up against diminishing returns. Considering an empty main file with just the main method, and including msp430.h is 107 bytes in size. .  . this is truly very tiny.

 

Next I plan on implementing a way to "format" output without writing multiple blocks of code for a few separate variables( on the same line of code ). I have a few ideas, but have no idea where this may lead for optimal code size / efficiency.

 

Size on target:

 

Writing  426 bytes at c000...
Writing   32 bytes at ffe0...
Done, 458 bytes total

 

 

hw_serial.h

 

namespace uart {

	template <uint32_t BAUD, uint32_t MCLK_HZ>
	struct UART
	{
		void Initialize(void);
		void Write(char ch);
		void Write(char *str);
		void Write(uint16_t value, uint8_t base);
	};

	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Initialize(void)
	{
		const uint32_t baud_rate_20_bit = (MCLK_HZ + (BAUD >> 1)) / BAUD;

		P1SEL |= BIT1 | BIT2;
		P1SEL2 |= BIT1 | BIT2;

		UCA0CTL1 = UCSWRST;                             
      	UCA0CTL0 = 0;                                   
      	UCA0BR1 = (baud_rate_20_bit >> 12) & 0xFF;    
      	UCA0BR0 = (baud_rate_20_bit >> 4) & 0xFF;      
      	UCA0MCTL = ((baud_rate_20_bit << 4) & 0xF0) | UCOS16; 
      	UCA0CTL1 = UCSSEL_2; 
	}
	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Write(char ch)
	{
		while(!(IFG2 & UCA0TXIFG));
		UCA0TXBUF = ch;
	}
	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Write(char *str)
	{
		while(*str) {
			Write(*str++);
		}
	}
	template <uint32_t BAUD, uint32_t MCLK_HZ>
	void UART<BAUD, MCLK_HZ>::Write(uint16_t value, uint8_t base)
	{
		char buffer[16];
		itoa(value, buffer, base);
		Write(buffer);
	}

} // end namespace

 

main.cpp

 

#include <msp430.h>
#include <stdlib.h>
#include "hw_serial.h"

using namespace uart;

UART<9600, 1000000> Serial;

int main(void)
{

	WDTCTL = WDTPW | WDTHOLD;

  DCOCTL = 0;
  DCOCTL = CALDCO_1MHZ;
  BCSCTL1 = CALBC1_1MHZ;
  BCSCTL2 = DIVS_0;

  Serial.Initialize();

  
  Serial.Write("Hello world\r\n");
  Serial.Write(1234, 10);

	return 0;
}


 

putty-output.jpg

Link to post
Share on other sites

So, I have been shown code that is at least 160 bytes smaller. So apparently I was not quite near diminishing returns.  Ah, well I will keep on experimenting and will let this person name them self, and show their own code when they are ready.

 

A bit of a teaser though, which I must say is very encouraging.

 

Writing  244 bytes at c000...
Writing   32 bytes at ffe0...
Done, 276 bytes total

 

output:

 

Hello world
10011010010 // 1234 in base 2 . . .

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...