Jump to content
43oh

woodgrain

Members
  • Content Count

    5
  • Joined

  • Last visited

Reputation Activity

  1. Like
    woodgrain reacted to RobG in MSP430F5510 USB Development Board   
  2. Like
    woodgrain reacted to RobG in MSP430F5510 USB Development Board   
    First batch ready for shipping.
    The board will come with unsoldered headers and switches and will look assembled like the one top center (that one is going to Energia folks, board #1 )
    The cost for the kit will be $55.10... just kidding, $15.
     
    Hope you enjoy it.
     

  3. Like
    woodgrain reacted to RobG in MSP430F5510 USB Development Board   
    MSP430F5510 development board, inspired by xpg, with LaunchPad compatible headers.
     




  4. Like
    woodgrain reacted to n1ksn in A brief state machine implementation tutorial   
    In this part we'll look at a couple of header files that are included in our Led.c module. The first is the file System.h which contains some global defines for our program:

    #ifndef SYSTEM_H #define SYSTEM_H #define FALSE 0 #define TRUE 1 #define NULL 0 // Each tick approximately 15.6 ms with ACLK at 32768 Hz (1 sec = 64 ticks) #define ACLK_FREQ 32768 #define TICK_DIVISOR 512 // In this version, set to match WDT interval #define TICKS_PER_SEC (ACLK_FREQ / TICK_DIVISOR) // Port and I/O pin bitmask definitions #define LEDOUT P1OUT #define LED1_BITMASK BIT0 #define LED2_BITMASK BIT1 #define LED3_BITMASK BIT2 #define BTNIN P1IN #define BTNIE P1IE #define BTNIFG P1IFG #define BTNIES P1IES #define BTNREN P1REN #define BTNOUT P1OUT #define BTN1_BITMASK BIT3 #define BTN2_BITMASK BIT4 #define BTN3_BITMASK BIT5 typedef void( * PFN )(void); // Pointer to function (void) foo(void) void System_InitializeHW(void); #endif
    After some initial defines for boolean values and NULL we have defines associated with the system tick. Our Led.c state machine module will be using the TICKS_PER_SEC value. Note that the module System.c sets up the watchdog timer to provide a ~15.6 ms system tick by putting the WDT in an interval mode, so these defines must coincide with that interval. (If you use a regular timer for the system tick, these defines help set that up.)
     
    The next four defines give aliases for the port(s) to which the LEDs are connected, and the bitmasks for them. This particular demonstration uses a single port, but each LED could be wired to a different port in which case aliases would be need for these. These defines aren't really necessary, as we could use P1OUT, BIT0, etc. in our module, but I like to localize pin assignments in the System.h header and System.c module. Below these are similar defines for the pushbutton module.
     
    Near the bottom of the header is a typedef for a pointer to a function which is of the "void foo(void)" variety, with no arguments and no return value. The name of the defined type is PFN (for "pointer to function") and it is the only function pointer type we will use. This state machine implementation uses a function pointer of this type to indicate the current state of the state machine. If you are not comfortable with function pointers in C, you should get to know them. They are our friends.
     
    Now let's look at the header Led.h:

    #ifndef LED_H #define LED_H // Each system tick approximately 15.6 ms with ACLK at 32768 Hz (64 ticks/sec) #define LED_DEFAULT_TICKS (TICKS_PER_SEC / 2) // Default blink half period #define LED_MAX_TICKS (32 * TICKS_PER_SEC) // Max ~ 1 cycle per minute #define LED_MIN_TICKS 2 // Should be at least 2 // Called by main at start-up void Led_InitializeHW(void); void Led_InitializeApp(void); // This function is called every system tick from main to drive // software timers for the LED state machines void Led_ProcessTimerEvents(void); //------------------------------------------------------------------------------ // Variable type and values to allow client module to specify LED typedef enum { LED_1 = 0, LED_2, LED_3 } Led_Index; #define LED_MAX 3 // Must coincide with typedef above // Functions to control LEDs from client module // Put LED in steady off state void Led_TurnOff(Led_Index index); // Put LED in steady on state void Led_TurnOn(Led_Index index); // Puts LED in last steady state void Led_Steady(Led_Index index); // Puts LED in blink state void Led_Blink(Led_Index index); // Sets LED on and off tick lengths (in system ticks), // restricted to range set by LED_MAX_TICKS and LED_MIN_TICKS. // Does not change current state of LED. void Led_SetBlink(Led_Index index, uint16_t on_ticks, uint16_t off_ticks); // Resets blink period to 2 * LED_DEFAULT_TICKS with 50% duty cycle // without changing LED state. void Led_ResetBlink(Led_Index index); // Retrieves current on_tick value of LED uint16_t Led_OnTicks(Led_Index index); // Retrieves current off_tick value of LED uint16_t Led_OffTicks(Led_Index index); #endif
    Here we first have a few more defines which depend on the TICKS_PER_SEC value. They set the default value for an LED blink period and the minimum and maximum number of system ticks for how long an LED can be off or on when blinking. The minimum value is the most important, as too short an interval could cause trouble with our blink software timer. The other two are arbitrary values.
     
    The next three statements are function prototypes which appear in this header so that the main module can call them. (This header is included in the main module.) The first two prototypes are for initialization of module-specific hardware and software on startup, and the third will be called by main on each system tick to operate the LED software timers used when they are blinking.
     
    The remainder of the function prototypes are the client interface for this module. Whichever modules that need to operate the LEDs will do so through these function calls. Their names are fairly self-explanatory. In order for a client to identify which LED is to be affected, the functions have the parameter "index" which is of type Led_Index. This is a custom type set up by the typedef enum statement just above these function prototypes. It is a combination of typedef and enum that defines a variable which can only take on the values enumerated in the definition. In this case there are three LED index values, LED_1, etc. Why do this typedef instead of using a regular old integer? It is a way to have the compiler flag some programmer mistakes that would set the index to a value outside the valid range for the LED index. (I don't think it will catch runtime errors, however.) In any case, it is a nice way to remember which index value goes with which LED. A companion define sets LED_MAX to the number of LEDs in our module.
     
    That's enough for this part. Next we'll (finally) start to look at the C code in Led.c.
     
    If you have any comments or questions about any of these posts, please don't hesitate to write a reply to this thread. I'll eventually include a zip file will all the program files in it.
     
    Later,
    Andy n1ksn
     
    Added in edit: I've added another client function prototype, namely for Led_Steady. This function returns the state machine to whatever steady substate was last active.
  5. Like
    woodgrain reacted to rockets4kids in Software async serial tx/rx without timer   
    I did not realize it at the time, but the code I was working from hed edits beyond oPossum's original code. I have gone back and re-patched for gcc from oPossum's code -- hopefully not introducing any new bugs this time!
     
    I did make one change, to re-name all the the public functions to start with "serial_" for the sake of clarity.
     
     
    serial.S

    #include #define PC r0 #define SP r1 #define SR r2 #define ARG1 R15 #define ARG2 R14 #define ARG3 R13 #define ARG4 R12 ; serial.asm .lcomm in_bit_mask, 2 ; Serial in pin .lcomm out_bit_mask, 2 ; Serial out pin .lcomm bit_dur, 2 ; Bit duration in cycles .lcomm half_dur, 2 ; Half bit duration in cycles ; .text ; .global serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .global serial_putc ; void serial_putc(unsigned c); .global serial_puts ; void serial_puts(char *s); .global serial_getc ; unsigned serial_getc(void); ; .p2align 1,0 ; align on a word boundary (GCC) ; serial_setup: ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov ARG1, &out_bit_mask ; Save serial output bitmask mov ARG2, &in_bit_mask ; Save serial input bitmask bis.b ARG1, &P1DIR ; Setup output pin bis.b ARG1, &P1OUT ; bic.b ARG2, &P1DIR ; Setup input pin bis ARG2, ARG1 ; bic.b ARG1, &P1SEL ; Setup peripheral select mov ARG3, ARG1 ; sub #16, ARG3 ; Adjust count for loop overhead rla ARG3 ; Multiply by 2 because NOP is two bytes mov ARG3, &bit_dur ; Save bit duration sub #32, ARG1 ; Adjust count for loop overhead mov ARG1, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char serial_putc: ; Char to tx in ARG1 ; ARG1, ARG2, ARG3, ARG4 trashed mov &out_bit_mask, ARG4 ; Serial output bitmask mov &bit_dur, ARG3 ; Bit duration bis #0x0300, ARG1 ; Stop bit(s) jmp bit_low ; Send start bit... ; tx_bit: mov ARG3, ARG2 ; Get bit duration tx_delay: nop ; 4 cycle loop sub #8, ARG2 ; jc tx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra ARG1 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b ARG4, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high: bis.b ARG4, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string serial_puts: ; Tx string using serial_putc push R11 ; mov ARG1, R11 ; String pointer in ARG1, copy to R11 putsloop: ; mov.b @R11+, ARG1 ; Get a byte, inc pointer tst.b ARG1 ; Test if end of string jz putsx ; Yes, exit... call #serial_putc ; Call serial_putc jmp putsloop ; putsx: pop R11 ; ret ; ; serial_getc: ; - Get a char mov &bit_dur, ARG3 ; Bit duration mov &in_bit_mask, ARG2 ; Input bitmask mov #0x01FF, ARG1 ; 9 bits - 8 data + stop ; rx_start: ; Wait for start bit mov.b &P1IN, ARG4 ; Get serial input and ARG2, ARG4 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, ARG2 ; Wait for 1/2 bit time ; rx_delay: nop ; Bit delay sub #8, ARG2 ; jc rx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov.b &P1IN, ARG4 ; Get serial input and &in_bit_mask, ARG4 ; rrc ARG1 ; Shift in a bit ; mov ARG3, ARG2 ; Setup bit timer jc rx_delay ; Next bit... ; rla ARG1 ; Move stop bit to carry swpb ARG1 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in ARG1, stop bit in carry ;
     
    serial.h

    void serial_setup (unsigned out_mask, unsigned in_mask, unsigned duration); void serial_putc (unsigned); void serial_puts (char *); unsigned serial_getc (void);
     
     
    main.c

    #include #include "serial.h" void main(void) { char c; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup (BIT1, BIT2, 1000000 / 9600); // Send a string serial_puts ("\r\nRunning...\r\n"); for (; { // Do forever c = serial_getc (); // Get a char serial_putc (c); // Echo it back } }
     
     
    Makefile

    main.elf: serial.S main.c msp430-gcc -Os serial.S main.c -o main.elf -mmcu=msp430g2211 install: main.elf mspdebug rf2500 "prog main.elf" clean: rm -f *~ *.elf
  6. Like
    woodgrain reacted to Rickta59 in Software async serial tx/rx without timer   
    Here is an msp430-gcc port of serial.S. Only some minor changes required:
     
    renamed from serial.asm to serial.S
    changed header inclusion, .cdecls to #include
    added ':' to all labels
    changed .bss directives to .lcomm
    changed .def directives to .global
    fixed argument registers CCS using R12-R15 for arg1-arg4, GCC uses R15-R12 for arg1-arg4
    reworked temp registers because of argument register reorder
    changed OR asm statements to BIS statements
     

    ; serial.S - gcc port of serial.asm #include ;------------------------------------------------------------------------------- ; --- define PC,SP,SR gcc only knows about registers --- #define PC r0 #define SP r1 #define SR r2 #define ARG1 R15 #define ARG2 R14 #define ARG3 R13 #define ARG4 R12 .lcomm in_bit_mask, 2 ; Serial in pin .lcomm out_bit_mask, 2 ; Serial out pin .lcomm bit_dur, 2 ; Bit duration in cycles .lcomm half_dur, 2 ; Half bit duration in cycles ; .text ; .global serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .global putc ; void putc(unsigned c); .global puts ; void puts(char *s); .global getc ; unsigned getc(void); ; .p2align 1,0 ; align on a word boundary serial_setup: ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov ARG1, &out_bit_mask ; Save serial output bitmask mov ARG2, &in_bit_mask ; Save serial input bitmask bis ARG1, &P1DIR ; Setup output pin bis ARG1, &P1OUT ; bic ARG2, &P1DIR ; Setup input pin bis ARG2, ARG1 ; bic ARG1, &P1SEL ; Setup peripheral select mov ARG3, ARG1 ; sub #16, ARG3 ; Adjust count for loop overhead rla ARG3 ; Multiply by 2 because NOP is two bytes mov ARG3, &bit_dur ; Save bit duration sub #32, ARG1 ; Adjust count for loop overhead mov ARG1, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char putc: ; Char to tx in R15 ; R12, R13, R14, R15 trashed mov &out_bit_mask, R12 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration bis #0x0300, ARG1 ; Add Stop bit(s) to tx char jmp bit_low ; Send start bit... ; tx_bit: mov R14, R13 ; Get bit duration tx_delay: nop ; 4 cycle loop sub #8, R13 ; jc tx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra ARG1 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b R12, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high: bis.b R12, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string puts: ; Tx string using putc push R11 ; mov ARG1, R11 ; String pointer in R15, copy to R11 putsloop: ; mov.b @R11+, ARG1 ; Get a byte, inc pointer tst.b ARG1 ; Test if end of string jz putsx ; Yes, exit... call #putc ; Call putc jmp putsloop ; putsx: pop R11 ; ret ; ; getc: ; - Get a char mov &bit_dur, R14 ; Bit duration mov &in_bit_mask, R13 ; Input bitmask mov #0x01FF, ARG1 ; 9 bits - 8 data + stop ; rx_start: ; Wait for start bit mov &P1IN, R12 ; Get serial input and R13, R12 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, R13 ; Wait for 1/2 bit time ; rx_delay: nop ; Bit delay sub #8, R13 ; jc rx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov &P1IN, R12 ; Get serial input and &in_bit_mask, R12 ; rrc ARG1 ; Shift in a bit ; mov R14, R13 ; Setup bit timer jc rx_delay ; Next bit... ; rla ARG1 ; Move stop bit to carry swpb ARG1 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in R15, stop bit in carry
     
    -rick
  7. Like
    woodgrain reacted to oPossum in Software async serial tx/rx without timer   
    Had some requests for this in IRC so here it is. This is an improved version of the serial tx previously posted and new serial rx code. Both tx and rx are blocking and interrupts should be disabled before calling.
     
    C code to show how to use the serial_setup(), putc(), puts(), and getc() functions.
    This will receive a character, increment it and echo it back. So if you type 'A', then 'B' will be echoed.

    // test.c #include "msp430g2211.h" // Functions in serial.asm (this really should be in a header file) void serial_setup(unsigned out_mask, unsigned in_mask, unsigned duration); void putc(unsigned); void puts(char *); unsigned getc(void); void main(void) { char c; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup(BIT1, BIT2, 1000000 / 9600); // Send a string puts("\r\nRunning...\r\n"); for(; { // Do forever c = getc(); // Get a char ++c; // Increment it putc(c); // Echo it back } }
     
    The serial tx/rx code. Just add this as a new source file in your CCS project and it will be callable from your C code.

    ; serial.asm .cdecls C, LIST, "msp430g2231.h" .bss in_bit_mask, 2 ; Serial in pin .bss out_bit_mask, 2 ; Serial out pin .bss bit_dur, 2 ; Bit duration in cycles .bss half_dur, 2 ; Half bit duration in cycles ; .text ; .def serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .def putc ; void putc(unsigned c); .def puts ; void puts(char *s); .def getc ; unsigned getc(void); ; ; serial_setup ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov R12, &out_bit_mask ; Save serial output bitmask mov R13, &in_bit_mask ; Save serial input bitmask bis.b R12, &P1DIR ; Setup output pin bis.b R12, &P1OUT ; bic.b R13, &P1DIR ; Setup input pin or R13, R12 ; bic.b R12, &P1SEL ; Setup peripheral select mov R14, R12 ; sub #16, R14 ; Adjust count for loop overhead rla R14 ; Multiply by 2 because NOP is two bytes mov R14, &bit_dur ; Save bit duration sub #32, R12 ; Adjust count for loop overhead mov R12, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char putc ; Char to tx in R12 ; R12, R13, R14, R15 trashed mov &out_bit_mask, R15 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration or #0x0300, R12 ; Stop bit(s) jmp bit_low ; Send start bit... ; tx_bit mov R14, R13 ; Get bit duration tx_delay nop ; 4 cycle loop sub #8, R13 ; jc tx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra R12 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low bic.b R15, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high bis.b R15, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string puts ; Tx string using putc push R11 ; mov R12, R11 ; String pointer in R12, copy to R11 putsloop ; mov.b @R11+, R12 ; Get a byte, inc pointer tst.b R12 ; Test if end of string jz putsx ; Yes, exit... call #putc ; Call putc jmp putsloop ; putsx pop R11 ; ret ; ; getc ; - Get a char mov &bit_dur, R14 ; Bit duration mov &in_bit_mask, R13 ; Input bitmask mov #0x01FF, R12 ; 9 bits - 8 data + stop ; rx_start ; Wait for start bit mov.b &P1IN, R15 ; Get serial input and R13, R15 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, R13 ; Wait for 1/2 bit time ; rx_delay nop ; Bit delay sub #8, R13 ; jc rx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov.b &P1IN, R15 ; Get serial input and &in_bit_mask, R15 ; rrc R12 ; Shift in a bit ; mov R14, R13 ; Setup bit timer jc rx_delay ; Next bit... ; rla R12 ; Move stop bit to carry swpb R12 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in R12, stop bit in carry ; .end ;
  8. Like
    woodgrain reacted to oPossum in Tiny printf() - C version   
    CCS requires labels in asm code to begin in the first column, so leading spaces will cause problems. This is typical for assembler code.
     
    Firefox may have problems with copy/paste from the forum. Chrome, Safari and IE seem to work as expected.
     
    To use the printf() with an LCD, just create a function named putc() that sends a single character to the LCD. If you find some sample code for LCD, there will probably a function that does this - just rename it.
     
    You will also need a puts() function. That can be this...
     

    void puts(char *s) { while(*s) putc(*s++); }
  9. Like
    woodgrain reacted to timotet in Tiny printf() - C version   
    So I tried just for fun to re-build the project from scratch.
     
    I started a new project in CCS.
    I copied the code from the beginning of this thread, and the serial.asm code from the post oPossum pointed out.
     
    3 separate files one project. Tried to compile no dice!
     
    compared the project with the one you posted that works great.
    The only difference I found was when I copied and pasted the .asm file from the the other post the file ends up indented
    to the right by 4 spaces in the editor window , and wont compile.
    I removed the 4 spaces from each line and it works great.
     
    Maybe this will help someone maybe not.
     
    thanks for the great code oPossum, and thanks for helping me get it going bluehash!
    This forum is awesome!!! :clap:
  10. Like
    woodgrain reacted to oPossum in Tiny printf() - C version   
    This is a tiny printf() function that can be used with the chips that come with the Launchpad. Code size is about 640 bytes with CCS.
     
    There are 7 format specifiers:
    %c - Character
    %s - String
    %i - signed Integer (16 bit)
    %u - Unsigned integer (16 bit)
    %l - signed Long (32 bit)
    %n - uNsigned loNg (32 bit)
    %x - heXadecimal (16 bit)
     
    Field width, floating point and other standard printf() features are not supported.
     
    printf() code

    #include "msp430g2231.h" #include "stdarg.h" void putc(unsigned); void puts(char *); static const unsigned long dv[] = { // 4294967296 // 32 bit unsigned max 1000000000, // +0 100000000, // +1 10000000, // +2 1000000, // +3 100000, // +4 // 65535 // 16 bit unsigned max 10000, // +5 1000, // +6 100, // +7 10, // +8 1, // +9 }; static void xtoa(unsigned long x, const unsigned long *dp) { char c; unsigned long d; if(x) { while(x < *dp) ++dp; do { d = *dp++; c = '0'; while(x >= d) ++c, x -= d; putc(c); } while(!(d & 1)); } else putc('0'); } static void puth(unsigned n) { static const char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; putc(hex[n & 15]); } void printf(char *format, ...) { char c; int i; long n; va_list a; va_start(a, format); while(c = *format++) { if(c == '%') { switch(c = *format++) { case 's': // String puts(va_arg(a, char*)); break; case 'c': // Char putc(va_arg(a, char)); break; case 'i': // 16 bit Integer case 'u': // 16 bit Unsigned i = va_arg(a, int); if(c == 'i' && i < 0) i = -i, putc('-'); xtoa((unsigned)i, dv + 5); break; case 'l': // 32 bit Long case 'n': // 32 bit uNsigned loNg n = va_arg(a, long); if(c == 'l' && n < 0) n = -n, putc('-'); xtoa((unsigned long)n, dv); break; case 'x': // 16 bit heXadecimal i = va_arg(a, int); puth(i >> 12); puth(i >> 8); puth(i >> 4); puth(i); break; case 0: return; default: goto bad_fmt; } } else bad_fmt: putc(c); } va_end(a); }
     
    test code

    #include "msp430g2231.h" void serial_setup(unsigned out_mask, unsigned in_mask, unsigned duration); void printf(char *, ...); void main(void) { char *s; char c; int i; unsigned u; long int l; long unsigned n; unsigned x; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup(BIT1, BIT2, 1000000 / 9600); printf("%s", "\r\n*** printf() test ***\r\n"); s = "test"; c = 'X'; i = -12345; u = 12345; l = -1234567890; n = 1234567890; x = 0xABCD; printf("String %s\r\n", s); printf("Char %c\r\n", c); printf("Integer %i\r\n", i); printf("Unsigned %u\r\n", u); printf("Long %l\r\n", l); printf("uNsigned loNg %n\r\n", n); printf("heX %x\r\n", x); printf("multiple args %s %c %i %u %l %n %x\r\n", s, c, i, u, l, n, x); printf("\r\n*** Done ***\r\n"); for(;; }

  11. Like
    woodgrain reacted to campbellsan in $4.30 LCD Booster - Sold Out   
    B#, I posted the code above as you suggested.
     
    I'd like to see it go into version control because I see more work being done on it and collaboration is more fun under a CM system.
     
    Note that this library relies on RobG's sed1565.h file available in the Code Vault. Thanks Rob.
    It does not rely on the sed1565.c file because I shamelessly plagiarised the parts of his excellent work I needed. Thanks Rob.
     
    This library also relies for text rendering on the font5x7.h file also available in the Code Vault. Another enhancement that occurs to me is to support all the fonts that I saw in there and have a font switch command, but that might start getting greedy on flash.
     
    Let's see where this goes. Enjoy!
     
    BTW, I'm sure no one expects any, but just in case, no warranties and all that usual stuff.... if heart monitor development is what you're doing with this, you're on your own. ;-)
  12. Like
    woodgrain reacted to campbellsan in $4.30 LCD Booster - Sold Out   
    Ok, good progress.
     
    I have a library that will plot lines, circles and text across the whole display.
     
    To use it, you make calls to draw_line, draw_text etc. and then call render. When render is called the resulting image is plotted to the screen. You can't make arbitrary draw calls straight to the screen for the reasons given earlier; it is not possible to read the controllers display memory, so plotting has to be done in SRAM before writing the data to the display. If we had enough SRAM, direct plotting would be possible. However 512 bytes in a MS430G2553 is only enough to cover less than 43 lines out of the possible 65 display lines and in any case, we need SRAM for variables and stack.
     
    Instead, I keep a command list and use a smaller buffer of 96 bytes. When you call a draw command, it is added to the command list. When render is called, the commands are plotted into the 96 byte buffer and written to the display. This is repeated 8 times to cover the whole display. This isn't CPU efficient, but it is SRAM efficient. With a little more work, the code could be enhanced so that you can trade off the size of the buffer against the number of times the renderer has to repeat the plotting behaviour and write the data. CPU efficiency aside, it manages 16 frames a second plotting a clock face. I have implemented some optimizations in the drawing algorithms so that overhead is reduced if a particular graphic has no presence in a particular strip of the output buffer, but more could be done.
     
    Another tradeoff which limits the complexity of the image is the size of the command buffer, this requires 5 bytes per command. I have thought about SRAM usage here too and provided an extended render command that allows the user to specify pre and post plot command lists which can be anywhere in memory, including flash. So you can plot a static background, some dynamic graphics and a static foreground. Of course, the back and foreground can be semi static, since you don't have to point at the same static command lists for every render_extended call.
     
    I found that the pixels are not square, so circles come out as ellipses. I added a y axis scaling factor to rectify this. You will be able to turn this off at compile time if you don't want it, but it is quite quick. Text output is not scaled so that the fonts look as they were intended to.
     
    Apart from the SRAM/CPU tradeoff enhancement, I was thinking of adding a simple draw_point command, an XOR drawing mode and shape fill capabilities.
     
    Please let me know what you would like to see.
     
    Library source:

    /* * sed1565gr.c * * Created on: May 12, 2012 * Author: campbell */ #include "msp430g2553.h" #include "sed1565gr.h" #include "sed1565.h" #include "stddef.h" #include"msp_intrinsics.h" #include"font_5x7.h" #include #include #define MAX_COMMANDS 10 #define BUFFER_SIZE 96 #define PAGE_SIZE 8 #define NUM_PAGES 9 // private data GR_CMD dynamic_command_list[MAX_COMMANDS]; char buffer[bUFFER_SIZE]; int cmd_index = 0; int extent_y; // private functions int buffers_remain(void); void prepare_context(void); void perform(GR_CMD command); void write_lcd(); void perform_line(DRAW_LINE_CMD* cmd); void perform_circle(DRAW_CIRCLE_CMD* cmd); void perform_text(DRAW_TEXT_CMD* cmd); void inline plot(int x, int y); void inline plot_raw(int x, int y); int abs(int arg); void clear() { cmd_index = 0; } void draw_line(char start_x, char start_y, char end_x, char end_y) { if (cmd_index < MAX_COMMANDS) { dynamic_command_list[cmd_index].cmd = CMD_LINE; dynamic_command_list[cmd_index].dlc.start_x = start_x; dynamic_command_list[cmd_index].dlc.start_y = start_y; dynamic_command_list[cmd_index].dlc.end_x = end_x; dynamic_command_list[cmd_index].dlc.end_y = end_y; cmd_index++; } } void draw_circle(char center_x, char center_y, char radius) { if (cmd_index < MAX_COMMANDS) { dynamic_command_list[cmd_index].cmd = CMD_CIRCLE; dynamic_command_list[cmd_index].dcc.center_x = center_x; dynamic_command_list[cmd_index].dcc.center_y = center_y; dynamic_command_list[cmd_index].dcc.radius = radius; cmd_index++; } } void draw_text(char x, char y, char *str) { if (cmd_index < MAX_COMMANDS) { dynamic_command_list[cmd_index].cmd = CMD_TEXT; dynamic_command_list[cmd_index].dtc.x = x; dynamic_command_list[cmd_index].dtc.y = y; dynamic_command_list[cmd_index].dtc.string = str; cmd_index++; } } void render() { render_extended(0, NULL, 0, NULL); } int bfr_indx; void render_extended(char pre_cmd_count, GR_CMD* pre_cmd_list, char post_cmd_count, GR_CMD* post_cmd_list) { prepare_context(); while (buffers_remain()) { bfr_indx = 0; // First render the passed command list, if one was passed while (bfr_indx < pre_cmd_count) { perform(pre_cmd_list[bfr_indx++]); } // Now render the dynamic command list bfr_indx = 0; while (bfr_indx < cmd_index) { perform(dynamic_command_list[bfr_indx++]); } // Now render the second passed command list, if there is one bfr_indx = 0; while (bfr_indx < post_cmd_count) { perform(post_cmd_list[bfr_indx++]); } write_lcd(); } clear(); } void perform(GR_CMD command) { switch (command.cmd) { case CMD_LINE: perform_line(&(command.dlc)); break; case CMD_CIRCLE: perform_circle(&(command.dcc)); break; case CMD_TEXT: perform_text(&(command.dtc)); break; default: //error case, halt break; } } int inline abs(int arg) { if (arg > 0) { return arg; } else { return -arg; } } void inline swap(int *a, int * { int temp = *a; *a = *b; *b = temp; } void perform_line(DRAW_LINE_CMD* cmd) { // Bresenham line algorithm int dx = (cmd->end_x - cmd->start_x); int dy = (cmd->end_y - cmd->start_y); int x = cmd->start_x; int y = cmd->start_y; int endx = cmd->end_x; int endy = cmd->end_y; plot(x, y); if (abs(dx) > abs(dy)) { if (x > endx) { swap(&x, &endx); swap(&y, &endy); dx = -dx; dy = -dy; } int p = (dy - dx) << 1; while (x <= endx) { if (p < 0) { x = x + 1; p = p + (dy << 1); } else { x = x + 1; y = y + 1; p = p + ((dy - dx) << 1); } plot(x, y); } } else { if (y > endy) { swap(&x, &endx); swap(&y, &endy); dx = -dx; dy = -dy; } int p = (dx - dy) << 1; while (y <= endy) { if (p < 0) { y = y + 1; p = p + (dx << 1); } else { x = x + 1; y = y + 1; p = p + ((dx - dy) << 1); } plot(x, y); } } } void perform_circle(DRAW_CIRCLE_CMD* cmd) { int x = 0; int y = cmd->radius; plot(cmd->center_x + x, cmd->center_y - y); int p = 3 - (cmd->radius << 1); for (x = 0; x <= y; x++) { if (p < 0) { p = (p + (x << 2) + 6); } else { y = y - 1; p = p + ((((x - y) << 2) + 10)); } plot(cmd->center_x + x, cmd->center_y - y); plot(cmd->center_x - x, cmd->center_y - y); plot(cmd->center_x + x, cmd->center_y + y); plot(cmd->center_x - x, cmd->center_y + y); plot(cmd->center_x + y, cmd->center_y - x); plot(cmd->center_x - y, cmd->center_y - x); plot(cmd->center_x + y, cmd->center_y + x); plot(cmd->center_x - y, cmd->center_y + x); } } void perform_text(DRAW_TEXT_CMD* cmd) { if (cmd->y >= extent_y - 7 && cmd->y < extent_y + PAGE_SIZE) { char * str = cmd->string; int col = 0; while (*str) { char c = *str++; int char_col = 0; while (char_col < 5) { char slice = font[c - 0x20][char_col]; int row = 0; while (row < 7) { if (slice & 0x01) { plot_raw(cmd->x + col, cmd->y + row); } slice = slice >> 1; row++; } char_col++; col++; } col++; } } } void inline plot(int x, int y) { #ifndef DONT_SCALE y -= (y >> 3); #endif plot_raw(x, y); } void inline plot_raw(int x, int y) { if (y >= extent_y && y < (extent_y + PAGE_SIZE)) { buffer[x] |= 1 << (y - extent_y); } } void prepare_context() { extent_y = -PAGE_SIZE; } void write_lcd() { int i = 0; // Set column to 0x12, the left hand edge of the LCD writeCommand(0x02); // Column Address LSN writeCommand(0x11); // Column Address HSN writeCommand(0xB0 | (extent_y >> 3)); // Page Address for (; i < BUFFER_SIZE; i++) { writeData(buffer[i]); } } int buffers_remain() { memset(buffer, 0, BUFFER_SIZE); extent_y += PAGE_SIZE; return NUM_PAGES - (extent_y >> 3); } void initLCD() { P2OUT |= LCD_ON_PIN + LCD_BL_PIN; _delay_cycles(0xffff); P1OUT |= LCD_RESET_PIN; writeCommand(DISPLAY_REVERSE); writeCommand(LCD_BIAS_1_7); writeCommand(ADC_SELECT_REVERSE); writeCommand(COMMON_OUTPUT_MODE_NORMAL); writeCommand(V5_VOLTAGE_REG_RATIO | 2); writeCommand(ELECTRONIC_VOLUME); writeCommand(0x2E); // 2E writeCommand(POWER_CONTROLLER_ALL_ON); writeCommand(0x40); // display start line 0 writeCommand(DISPLAY_ON); } void write(char data, char registerSelect) { char c = 0; LCD_SELECT; registerSelect ? (SET_DATA) : (SET_COMMAND); while (c < 8) { (data & BIT7) ? (P2OUT |= LCD_SDATA_PIN) : (P2OUT &= ~LCD_SDATA_PIN); LCD_CLOCK; data <<= 1; c++; } LCD_DESELECT; }
     
    Library Header:

    /* * sed1565gr.h * * Created on: May 12, 2012 * Author: campbell */ #ifndef SED1565GR_H_ #define SED1565GR_H_ #include "sed1565.h" #include enum CMD { CMD_LINE, CMD_CIRCLE, CMD_ELLIPSE, CMD_TEXT }; typedef struct { char start_x; char start_y; char end_x; char end_y; } DRAW_LINE_CMD; typedef struct { char center_x; char center_y; char radius; } DRAW_CIRCLE_CMD; typedef struct { char center_x; char center_y; char focus_a; char focus_b; } DRAW_ELLIPSE_CMD; typedef struct { char x; char y; char * string; } DRAW_TEXT_CMD; union { DRAW_LINE_CMD dlc; DRAW_CIRCLE_CMD dcc; DRAW_ELLIPSE_CMD dec; DRAW_TEXT_CMD dtc; } DRAW_CMD_DATA; typedef struct { enum CMD cmd; union { DRAW_LINE_CMD dlc; DRAW_CIRCLE_CMD dcc; DRAW_ELLIPSE_CMD dec; DRAW_TEXT_CMD dtc; }; } GR_CMD; void clear(); void draw_line(char start_x, char start_y, char end_x, char end_y); void draw_circle(char center_x, char center_y, char radius); void draw_ellipse(char center_x, char center_y, char focus_a, char focus_; void draw_text(char x, char y, char * str); void render(); void render_extended(char pre_cmd_count, GR_CMD* pre_commmand_list, char post_cmd_count, GR_CMD* post_command_list); #endif /* SED1565GR_H_ */
     
    Example main:

    /* * main.c */ #include "msp430g2553.h" #include "msp_intrinsics.h" #include #include "sed1565gr.h" char * msg = "www.43oh.com"; void main(void) { WDTCTL = WDTPW + WDTHOLD; // disable WDT BCSCTL1 = CALBC1_16MHZ; // 16MHz clock DCOCTL = CALDCO_16MHZ; P1OUT &= ~LCD_RESET_PIN; // keep low until init P1DIR |= LCD_RESET_PIN; P2OUT |= LCD_SCLK_PIN + LCD_CS_PIN + LCD_SDATA_PIN + LCD_DC_PIN + LCD_ON_PIN + LCD_BL_PIN; P2DIR |= LCD_SCLK_PIN + LCD_CS_PIN + LCD_SDATA_PIN + LCD_DC_PIN + LCD_ON_PIN + LCD_BL_PIN; initLCD(); draw_circle(48, 37, 36); draw_line(48, 38, 46, 5); draw_line(48, 38, 60, 55); draw_text(14, 48, msg); render(); }
  13. Like
    woodgrain reacted to bluehash in SDCard Booster Pack   
    Just came in today along with the Wiznet Wifi PCBs



    First test successful with code from here.
    Card detect LED needs to be added in. Currently running on a 2553 USCI. Jumper support is available for 2452 USI too.





    Schematics in a few days. I'm too tired right now.

    Latest code:
    Code

    Suggested for Next Rev:
    1.Add mini SD support
    2.Wire gnd line to pid 6 of sd card connector. Thanks Rick!
    3. Add micro SD support?
    4. Dac/LM386(<-Rick's suggestion)
  14. Like
    woodgrain reacted to RobG in (Universal) Color LCD graphics library   
    New versions are here
     
    UPDATE: Sep 3rd 2013
    New way to configure dev boards
    Works with TI's G2 LaunchPad (G2553,) and my G2955, F5172, F5510, F5529 dev boards.
    Just one line change to switch between the boards.
    Hardware and software SPI.
    Supported drivers:
    ILI9340/ILI9341 (2.2" 320x240)
    ST7735R (JD-T1800, 1.8" LCD) needs extra work
    HX8340B (BTL221722, 2.2" without touch) needs extra work
    ILI9225B (2.2" with touch) needs extra work
    09032013.zip
     
    UPDATE: Aug 15th 2013
    Added support for large displays, 320 x 240
    Added rotation at run time (only ILI9340/41 at this time.)
    Supported drivers:
    ILI9340/ILI9341 (2.2" 320x240)
    ST7735R (JD-T1800, 1.8" LCD) needs extra work
    HX8340B (BTL221722, 2.2" without touch) needs extra work
    ILI9225B (2.2" with touch) needs extra work
    081513-16.zip
     
    UPDATE: May 6th 2013
    Added support for horizontal orientation
    Added support for hardware SPI
    Removed support for Nokia displays and 8bit color.
    Supported drivers:
    ST7735R (JD-T1800, 1.8" LCD)
    HX8340B (BTL221722, 2.2" without touch)
    ILI9225B (2.2" with touch)
    050613files.zip
     
    Older files
    Supported drivers:
    PCF8833 (Nokia 6100)
    SPFD54124B (Nokia 6085 and 6101)
    ST7735R (JD-T1800, 1.8" LCD)
    HX8340B (BTL221722, 2.2" without touch)
    ILI9225B (2.2" with touch)
    pre050613files.zip
     


×
×
  • Create New...