Jump to content
monsonite

SIMPL - A Tiny Language for MSP430

Recommended Posts

Hi All

 

Back in May 2013, I came across a piece of development work by Ward Cunningham (wiki inventor) for a tiny interpreted language "Txtzyme" that ran on Arduino - or virtually any other micro that was supported by a C compiler.

 

(The name Txtzyme comes from text and enzyme -  an enzyme being a biological catalyst - or a substance that causes (chemical) change to occur faster).

 

I was intrigued how under 100 lines of C code formed such a useful and extendable language - that I quickly had it running on an Arduino, and was making my own modifications and improvements.  I have since built on Ward's work and called my project SIMPL - Serial Interpreted Microcontroller Language.

 

(Link to Ward's original work is here  https://github.com/WardCunningham/Txtzyme )

 

Ward had created a "nano interpreter" in just a few lines of C code, which formed the heart of an interactive language for controlling hardware.

 

Through just a dozen commands it would allow port manipulation,  flashing LEDs,  musical tone generation, PWM, printing to screen and sensing analogue signals. The language communicated through a uart port to the PC.

 

Originally Txtzyme offered just these commands - see Ward Cunningham's Read Me:

a-f      Select an I/O port
h        help - a summary of commands
i         input
k        a loop counter - which decrements each time around the loop  see {}
m       millisecond delay
o       output
p       print the value of variable x followed by carriage return/line feed
s       sample an ADC channel
u       microsecond delay
x       a 16 bit integer variable
{}     code between these braces is repeated as a loop
_ _    characters between the underscores are printed to the terminal

 

Txtzyme was small, entensible and portable - it will run on almost any microcontroller.  The Txtzyme scripts were very small, human readable and easy to send from one device to another.

 

One early application was for the Arduino to be used as an I/O controller board attached to a Raspberry Pi.  The Pi would send a simple command via it's uart and the Arduino would perform an I/O function, sequence or whatever.

 

Some months later, I decided to try Txtzyme with the MSP430, as I had got a LaunchPad and Energia had just appeared on my radar. 

So I took the original Txtzyme Arduino  sketch, loaded into Energia - and behold it worked first time.  Txtzyme was a universal "lingua franca" that could be used on any micro.

 

If you want to try  arecent version of SIMPL that runs on a LaunchPad MSP430G2553 - here is the Github Gist

 

https://gist.github.com/anonymous/034dd41f108263d09803

 

Since then I have ported it to  AVR Cortex M3, M4,  and several soft-core processors running on FPGAs.

 

Currently my aim is to reduce the SIMPL Kernel to approximately 2kbytes - so that it can become a "Smart Bootloader"  - residing on the microcontroller in the bootloader area, and being immediately available as an interactive toolkit for exercising hardware and performing small applications.

 

I have written extensively about it in my blog  - starting here  from May 2013

 

http://sustburbia.blogspot.co.uk/2013/05/txtzyme-minimal-interpreter-and.html

 

I have also just this week started a wiki - so that all the new information can reside in 1 place.

 

https://simplex1.wiki.zoho.com/HomePage.html

 

 

Please get in touch if you would like to know more about SIMPL and my project aims.  

 

 

 

 

Ken 

 

London

 

 

 

 

 

 

Share this post


Link to post
Share on other sites

Wow this is really cool. I'd never heard of txtzyme before.

 

What extra commands have you added in your version? I skimmed the code and I see

[] Conditional branches
!@ store and fetch
Logical operators

along with alot more IO stuff, analog/digital

 

My first micro controller experience was the PICAXE platform. and it was developed in a similar way. You would write BASIC code. it was 'compiled' into something like this (maybe less human readable) and loaded into the PIC's EEPROM via a UART connection. It was then run by an interpreter which was actually the code inside the PIC's memory.

Share this post


Link to post
Share on other sites

Hi

 

I have just started the SIMPL Wiki in my GitHub space - sorry there are some formatting errors.

 

You can view it here

 

https://github.com/m...nite/SIMPL/wiki

 

 

Fundamentally, SIMPL uses single ASCII character tokens for all it's instructions/commands - so a switch-case statement can be used to decode them and call the associated functions.

 

There are about 50 instructions built into the kernel.   Users can then compose their own words/phrases based on these instructions and allocate to them a single upper case letter.  When this upper case letter is encountered, all of the underlying code is executed.

 

Essentially its a form of bytecode - but with the emphasis on human readability.

 

The space character has special meaning however - and cannot be used for "whitespace".

 

When you want to perform a maths operation on two operands, the single space between operand x and y informs the interpreter to shunt x into a second variable location making room for y.  The instruction can then operate on x and y.

 

This is in effect a very limited form of stack architecture   consisting of a top of stack and a next on stack.

 

SIMPL has been influenced by Forth - but has had to make simplifications in order to fit in a very small code space - complete with all the I/O, peripherals  and comms routines.

 

 

 

 

Here's a copy

 

The SIMPL Instruction Set

 

   

The SIMPL Instruction Set builds upon the Txtzyme instructions, adding more instructions and program flow operators.
 
In general lower case characters a-z are used for calling functions, consisting of one or more instructions. 
 
a          Assemble
b          Block
c          Compile
d          Dump
e          Edit
f           File
g          Go
h          High
i           Input
j           Jump
k          Count
l           Low
m         Milliseconds
n          Number
o          Output
p          Print
q          Query
r           Read
s          sample
t           Time
u          Microseconds
v          Variable
w         Write
x          X reg
y          Y reg
z          Snooze
 
 
The arithmetical and punctuation characters are used for lower level instructions - for example he arithmetical and logical group:
 
+      ADD 
-       SUB
*       MUL
/       DIV
%     MOD
 
&      AND
|       IOR
^      XOR
~      NOT
 
Conditional Tests
 
<      LT
>      GT
=      EQ
 
There are then the memory operations - borrowed from Forth
 
@   Fetch
!      Store
 
?    Query  - List the dictionary of words
 
,      Comma separate items within an array
 
Instruction grouping  - as per Txtzyme,  plus new ones
 
_string_        Print the characters enclosed between the underscore
 
"           "  
 
{loop}           The code between the braces is looped
 
[1,2,3,4,5]   Define a comma separated array
 
x(1,2,3,4)       Switch/Case - the case x is selected from the enclosed list
 
\text\             The text between the forward slashes is copied to external RAM
 
#                   convert number to ASCII  
 
$                   convert number to HEX
 
:                    Begin a colon definition
;                    Close a colon definition    (Compile it)
 

Share this post


Link to post
Share on other sites

Hello All

 

 

 

My MSP430FR4133 Launchpads turned up this morning and it was quite quick and easy to port SIMPL across to it - from previously on the MSP430G2533

 

I have included the code below.

 

The UART is running at 125000 Baud -  a simple binary division of the 8MHz clock.   I use Termite or Terraterm - which will handle these non standard baudrates.

 

The SPI RAM is connected to USCB0   - see this blogpost for preliminary details.

 

On the '4133 Launchpad the following connections are needed

 

MOSI           P5.2

MISO           P5.3

SCLK           P5.1

/RAM_CS    P8.0

 

http://sustburbia.blogspot.co.uk/2016/03/interfacing-spi-sram-fram-to-msp430.html 

 

 

I've got the display to display integers <100, with some rather dirty code!

 

 

In the future I like the look of the new low cost, low pin-out  FRAM based   FR24xx, FR25xx and FR26xx series as potential targets for SIMPL

// SIMPLEX 2_MSP430FR4133_5
// - inspired by Txtzyme Nano Interpreter -  an original idea by Ward Cunningham

// An on going Neo-Retro Computing Mission!
// Ken Boak  March 9th 2016

// SIMPL Interpreter for MSP430FR4133 Launchpad

// This version adds 23K256 32Kx8 external SPI RAM, plus hex-dump utlity
// With addition of timing routines and other debug 
// MSP430FR4133 UART, SPI and LCD suport Routines 
// - codesize is now 4167 bytes

// This version for FRAM based MSP430 with MSP430FR4133 Launchpad compiled using Energia 
// Note - serial uart on P1.1 and P1.2 is running at odd-baud  of 100,000 bits/s  - to be investigated

// This version includes the t and v functions to determine timing tests - note  millis is running at 16 times speed!
// Any time entered for m or u is multiplied by 16
// Any time printed out from b or c id divided by 16!
// There is a debug pin on P1.0 (Green LED) which allows scope probe attachment to confirm times

// RAM connections
/*
              +------U------+
P8.0  /CE     |   23K256    | 3V3
P5.2  MISO    |             | HOLD - pull up to 3V3
      NC      |             | SCK  - P5.1
      0V      |             | MOSI - P5.2
              +-------------+
*/
// Timing

// 1,000,000 empty loops in 2.4uS per iteration
// 100,000,000 empty loops in 2.4uS per iteration

#include <MSP430FR4133.h>

#define        RXD	       BIT1                // Receive Data (RXD) at P1.1
#define        TXD	       BIT2                // Transmit Data (TXD) at P1.2
#define        RED             0x20                // Red LED is on Bit 6    
#define        GREEN           0x01                // Green LED is on Bit 0
//#define        SS_PIN          BIT4                // CS , active low
#define        SS_PIN          BIT0                // CS , active low  Port 8.0
#define        DEBUG_PIN       BIT0                // toggle on and off marking time to write
#define        DUMMY_BYTE      0xFF                // byte we send when we just want to read slave data
//#define        ssSelect        P1OUT &= ~SS_PIN
//#define        ssDeselect      P1OUT |= SS_PIN
#define        ssSelect        P8OUT &= ~SS_PIN
#define        ssDeselect      P8OUT |= SS_PIN

#define delay_1ms __delay_cycles(16000)
#define bufRead(addr)       (*(unsigned char *)(addr))
#define bufWrite(addr,    (*(unsigned char *)(addr) = ()
#define bit0 0x01   // 1
#define bit1 0x02   // 2
#define bit2 0x04   // 4
#define bit3 0x08   // 8
#define bit4 0x10   // 16
#define bit5 0x20   // 32
#define bit6 0x40   // 64
#define bit7 0x80   // 128
#define SR_WRITE_STATUS 0x01
#define SR_WRITE        0x02
#define SR_READ         0x03
#define SR_READ_STATUS  0x05
#define BYTES_TO_STREAM 1024     // should be less <= 32768
#define PATTERN_BYTE_VALUE 65

//---------------------------------------------------------------------------------
// LCD defines

#define pos1 4                                                 // Digit A1 - L4
#define pos2 6                                                 // Digit A2 - L6
#define pos3 8                                                 // Digit A3 - L8
#define pos4 10                                                // Digit A4 - L10
#define pos5 2                                                 // Digit A5 - L2
#define pos6 18                                                // Digit A6 - L18

const char digit[96] =                                        // Array to hold digits, upper case alpha and punctuation
{
    0xFC,                                                      // "0"
    0x60,                                                      // "1"
    0xDB,                                                      // "2"
    0xF3,                                                      // "3"
    0x67,                                                      // "4"
    0xB7,                                                      // "5"
    0xBF,                                                      // "6"
    0xE4,                                                      // "7"
    0xFF,                                                      // "8"
    0xF7                                                       // "9"
};
//---------------------------------------------------------------------------------

static inline uint8_t RWData(uint8_t value);
int spi_rx_data = 0 ;


//-----------------------------------------------------------------
// This character array is used to hold the User's words - on the '2553 we only have 512 bytes of RAM

char array[6][32] =      {
                         {"_Hello World, welcome to SIMPL_"},
                         {"_Mary had a Little Lamb_"},
                         {"_This is a test message_"},
                         {"_Hickory, Dickory Dock_"},
                         {"_twas brillig slithy toves_"},
                         {"11{kp_ Green Bottles_}"}
                         
                         };
 
    char buf[64];                          // Buffer to hold users keyboard entry                           
    char num_buf[11];                      // long enough to hold a 32 bit long
    char block_array[33];                  // Used to transfer bytes from external RAM and execute x-code      
                        
//    int a = 0;                          // integer variables a,b,c,d
//    int b = 0;
//    int c = 0;
//    int d = 6;                          // d is used to denote the digital port pin for I/O operations

    unsigned long x = 0;                // Three gen purpose variables for stack & math operations
    unsigned long y = 0;
    unsigned int  z = 0;
    unsigned int ADC_value=0;
    
    int hex_value = 0;
    int dec_value = 0;
    int decimal_value = 0;
    char ha = 0;
    char hex_char; 

    unsigned char in_byte;
 
    int len = 32;                        // the max length of a User word
    int length = 0;                      // number of bytes to red/write to SRAM
    int address = 0 ;                    // starting address of RAM R/W streamms
    int RAM_byte =0;                     // contents of RAM at given location    
    long old_millis=0;
    long new_millis=0;
    unsigned long time = 0;    
    char  name;    
    char* parray;
    char* px_array;       
    char* addr;
    char mode = 0x41;                  // Sequential mode for SRAM
    
    unsigned int num = 0;
    unsigned int num_val = 0;
    int j;
/*
//---------------------------------------------------------------------
// Initialise the USCI B for Master Mode SPI
//---------------------------------------------------------------------    
// recommended procedure: set UCSWRST, configure USCI, configure ports, activate 
//---------------------------------------------------------------------    
void spi_init(void)
{
  
//---------------------------------------------------------------------
// Configure the Clock for 16 MHz
  BCSCTL1 = CALBC1_16MHZ;  
  DCOCTL =  CALDCO_16MHZ;

//---------------------------------------------------------------------
//  Set  UCSWRST 
  UCB0CTL1 = UCSWRST;

//---------------------------------------------------------------------    
// Configure USCI B0 
  UCB0CTL0 |= UCCKPH + UCMSB + UCMST + UCSYNC;     // 3-pin, 8-bit SPI master
  UCB0CTL1 |= UCSSEL_2;                            // SMCLK
  UCB0BR0 |= 2;                                    // 8 MHz SPI-CLK
  UCB0BR1 = 0;
//UCB0MCTL = 0;

//---------------------------------------------------------------------    
// Configure  Ports
  P1SEL |= BIT5 + BIT6 + BIT7;
  P1SEL2 |= BIT5 + BIT6 + BIT7;
  P1DIR |= BIT0 + BIT4 + BIT5 | BIT7;

//---------------------------------------------------------------------    
// activate 
  UCB0CTL1 &= ~UCSWRST;  
}

*/
//--------------------------------------------------------------------------------
// SPI Initialisation for MSP430FR4133 LaunchPad
//--------------------------------------------------------------------------------
//  P5.3 MISO
//  P5.2 MOSI
//  P5.1 SCLK
//  P8.0  /RAM_CS

void spi_init_4133()

{
// Configure GPIO
 P8DIR |= BIT0;                          // For /RAM_CS
 P5SEL0 |= BIT1 | BIT2 | BIT3;           // SCLK, MISO, MOSI pins
 
// Configure USCI_B0

    UCB0CTLW0 |= UCSWRST;                     // **Put state machine in reset**
    UCB0CTLW0 |= UCMST|UCSYNC|UCCKPH|UCMSB;   // 3-pin, 8-bit SPI master
                                              // Clock polarity low, MSB 
    UCB0CTLW0 |= UCSSEL_2 ;                   // SMCLK
    UCB0BR0 = 0x01;                           // /2,fBitClock = fBRCLK/(UCBRx+1).
    UCB0BR1 = 0;                              //

    UCB0CTLW0 &= ~UCSWRST;                    // **Initialize USCI state machine**
}



//--------------------------------------------------------------------------------
// 23K256 Serial Ram functions
//--------------------------------------------------------------------------------

uint8_t SR_getMode(void) {                                    // Read the Mode of the 23K256
    ssSelect;                                                 // select
    RWData(SR_READ_STATUS); // 0x05
    uint8_t mode = RWData(DUMMY_BYTE);
    ssDeselect;                                               // de-select
    return mode;
}

void SR_setMode(uint8_t mode) {                               // Write Mode to 23K256
    ssSelect;
    RWData(SR_WRITE_STATUS); // 0x01
    RWData(mode);
    ssDeselect;
}

static inline void SR_writestream(uint16_t addr) {          // Write a stream to 23K256
    ssDeselect; // deselect if we are active
    ssSelect;
    RWData(0x02);                                           // Send command
    RWData(addr >> 8);                                      // Send upper address
    RWData(addr);                                           // Send lower address
}

static inline void SR_readstream(uint16_t addr) {             // Read a stream from 23K256
    ssDeselect;
    ssSelect;
    RWData(0x03);                                            // Send command
    RWData(addr >> 8);                                       // Send upper address
    RWData(addr);                                            // Send lower address
}

//-----------------------------------------------------------------
// SPI Send / Receive

static inline uint8_t RWData(uint8_t value) 
{
    UCB0TXBUF = value;
//    while (!(IFG2 & UCB0TXIFG)) {};        // wait for buffer ready
      while (!(UCB0IFG & UCTXIFG)) {};        // wait for buffer ready
//    while  (!(IFG2 &   UCB0RXIFG));        //  USCI_B0 RX  Received?
    while  (!(UCB0IFG &   UCRXIFG));        //  USCI_B0 RX  Received?
    spi_rx_data    =   UCB0RXBUF;          //  Store received data
    return  spi_rx_data;
}

//------------------------------------------------------------------------------------
// UART Initialisation
// UART provides PC comms on 1.2 and P1.2 - uses USCI A

void uart_init_4133(void)

{

 // Configure UART pins
  P1SEL0 |= BIT0 | BIT1;                    // set 2-UART pin as second function

  // Configure UART
  UCA0CTLW0 |= UCSWRST;
  UCA0CTLW0 |= UCSSEL__SMCLK;
  
  // Baud Rate calculation
  // 8000000/(16*9600) = 52.083
  // Fractional portion = 0.083
  // User's Guide Table 14-4: UCBRSx = 0x49
  // UCBRFx = int ( (52.083-52)*16) = 1
  UCA0BR0 = 4;                             // 8000000/16/9600
  UCA0BR1 = 0x00;
  UCA0MCTLW = 0x5500 | UCOS16 | UCBRF_1;

  UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI


}

/*

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

*/

//--------------------------------------------------------------------- 
// UART Primitive Routines uart_putc and uart_get_c

unsigned char uart_getc()
{
//    while (!(IFG2&UCA0RXIFG));                   // USCI_A0 RX buffer ready?
    
     while (!(UCA0IFG&UCRXIFG));                   // USCI_A0 RX buffer ready?
     return UCA0RXBUF;
}

void uart_putc(unsigned char c)
{
	while (!(UCA0IFG&UCTXIFG));              // USCI_A0 TX buffer ready?
  	UCA0TXBUF = c;                          // TX
}

void uart_puts(const char *str)                 // Output a string 
{
     while(*str) uart_putc(*str++);
}

//------------------------------------------------------------------------
// Print a long unsigned int number 

  void printlong(unsigned long num)
  {
  if (num / (unsigned long)10 != 0) printlong(num / (unsigned long)10);
  uart_putc((char)(num % (unsigned long)10) + '0');   
  return;
  }
//---------------------------------------------------------------------------  
// Print a CR-LF

  void crlf(void)                  // send a crlf 
  {  
    uart_putc(10);
//  uart_putc(13); 
  }
    
  void print_ok()
  {uart_puts((char *)"OK\n\r"); }   
 
 //------------------------------------------------------------------------------------
 // Initialise the ADC on the '4133
 
void ADC_init_4133(void)
{
} 


  

/*
//-------------------------------------------------------------------------------------
// ADC Configuration

  void ConfigureAdc(void)
{
  ADC10CTL1 = INCH_3 + ADC10DIV_3 ;                     // Channel 3, ADC10CLK/3
  ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;  // Vcc & Vss as reference, Sample and hold for 64 Clock cycles, ADC on, ADC interrupt enable
  ADC10AE0 |= BIT3;                                     // ADC input enable P1.3
}

 int ADC_Read(void) 
 {
   ADC10CTL0 |= ENC + ADC10SC;			// Sampling and conversion start
   ADC_value = ADC10MEM;
   return ADC_value;
 } 
*/
//-------------------------------------------------------------------------------------
// mS delay routine

void delay_mS(int j)
{
    volatile unsigned long i;   
           while(j)
  {           
           i = 42;             	         // Delay
   	   do (i--);	 
           while (i != 0);	        // busy waiting (bad)
           j--;
  }	  
}
//---------------------------------------------------------------------------------

void setup(void)
{
        WDTCTL  = WDTPW + WDTHOLD; 	             // Stop WDT
        
        PM5CTL0 &= ~LOCKLPM5;                       // Disable the GPIO power-on default high-impedance mode
        
//        Serial.begin(100000);                        // initialises timing functions
        
//	BCSCTL1 = CALBC1_1MHZ;                       // Set DCO
//  	DCOCTL  = CALDCO_1MHZ; 
	P1DIR  = BIT0 + BIT6; 		              // P1.0 and P1.6 are the red+green LEDs	
	P1OUT  = BIT0 + BIT6; 		              // All LEDs off

        uart_init_4133();                                  // Initialise the '4133 UART for 96000 baud

        spi_init_4133();                                   // Initialise the '4133 SPI on USCIB  8MHz clock, master mode
        
        uart_puts((char *)"MSP430 SIMPLEX\n\r");      // send opening banner message
        
        spi_check();                                  // Make sure SPI RAM is connected and in the correct streaming mode
                
 //       P1SEL |= BIT3;	                              // ADC input pin P1.3
        ADC_init_4133();		
        WDTCTL = WDTPW + WDTTMSEL + WDTIS1;            // enable watchdog - interval mode
        parray = &array[0][0];                        // parray is the pointer to the first element of code buffer      
        px_array = &block_array[0];                   // px_array is pointer to first element of RAM transfered block array
        delay(1);
        time = micros();
        printlong(time);                 // used for timing functions
        crlf();
        
        LCD_print_4133();
}
void  loop(void)
{  
//-------------------------------------------------------------------------------    
// Interpreter Loop
  while(1)
  {  

  textRead(buf, 64);                                  // This is the endless while loop which implements the SIMPL interpreter - just 3 simple functions
  textChk(buf);                                       // check if it is a : character for beginning a colon definition   
  textEval(buf);
    
  }   // end of interpreter loop
  
}    // End of main

//-------------------------------------------------------------------------------    
// Language Functions  - Words
// ------------------------------------------------------------------------------

//  Read the character into the buffer

void textRead (char *p, byte n) {
  byte i = 0;
  while (i < (n-1)) {
    char ch = uart_getc();
    if (ch == '\r' || ch == '\n') break;
    if (ch >= ' ' && ch <= '~') {
      *p++ = ch;
      i++;
    }
  }
  *p = 0;
}

// --------------------------------------------------------------------------------------------------------- 
void textChk (char *buf)       // Check if the text starts with a colon and if so store in user's word RAM array  parray[]
{       
  if (*buf == ':')  {  
  char ch;
  int i =0;
  while ((ch = *buf++)){
    
  if (ch == ':') {
  uart_putc(*buf);   // get the name from the first character
  uart_putc(10);
  uart_putc(13);
  name = *buf ;
  buf++;
  }
 
  bufWrite((parray + (len*(name-65) +i)),*buf);
   
  i++;
 
}

 x = 1;
 
} 
}

// --------------------------------------------------------------------------------------------------------- 

void textEval (char *buf) {
  
  char *loop;
  char *start;
  char ch;
  
  unsigned long k = 0;
   
  while ((ch = *buf++)) {                         // Is it a number?
    switch (ch) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      x = ch - '0';
      while (*buf >= '0' && *buf <= '9') {
        x = x*10 + (*buf++ - '0');                // If  a number store it in "x"
      }
      break;
      
//-------------------------------------------------------------------------------     
 // User Words   
      case 'A':                // Point the interpreter to the array containing the words
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':    
      case 'I':               
      case 'J':
      case 'K':
      case 'L':
      case 'M':
      case 'N':
      case 'O':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
      case 'T':
      case 'U':
      case 'V':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
     
      textEval(parray + (len*(ch-65)));            // Evaluate and execute the User's expression fo RAM
      
      break;
     
//---------------------------------------------------------------------------------    
//  (a - h  hijacked for SPI RAM extensions - SIMPLEX!)   
   
      case 'a':         // Address  (for writing to RAM)
      address =(x);
      break;
      
      case 'b':         // Block   - fetch a block from external memory
      get_block(x);
      break;
      
      case 'c':         // Compile      
      hex_print_2(x);
      break;
      
      case 'd':         // HEX Dump  -  dump x bytes starting at address y
      hex_dump(y,x);
      print_ok();      
      break;
      
/*      
      case 'd':         // Decimal Dump
      dump(y,x);        // dump y bytes starting at address x
      break;
*/      
      case 'e':         // Execute      
      execute_block(x);
      break;
      
      case 'f':         // File  // fill y bytes starting at address x with test data
      spi_fill(y,x);  
      print_ok();    
      break;
      
      case 'g':         // Go
      run_block();
      break;
      
      case 'n':         // Go
      LCD_display_n(x);
      break;

//-------------------------------------------------------------------------------- 
// Primitive and User vocabulary defined in this section      
// Timing & Printing Group

      case 'p':
      printlong(x);                        // print long integer
      break;

      case 'q':                            // print integer with crlf
      printlong(x);
      crlf();
      break;
            
      case 't':
      time = micros();
      printlong(time/16);                 // used for timing functions
      crlf();
      break;
      
      case 'v':
      time = micros();
      printlong(time/16);                 // used for timing functions
      crlf();
      break;

/*      
      case 'd':
      d = x;
      break;
*/

      case '_':                              // Print the string enclosed between underscores  eg.  _Hello_
      while ((ch = *buf++) && ch != '_') {
      uart_putc(ch);
      }
      uart_putc(10);
      break; 
      
      case 92 :                              //  ASCII 92 forward slash \ Copy the text enclosed between \ and \ to RAM 
      while ((ch = *buf++) && ch != 92) {
      uart_putc(ch);
      }
      uart_putc(10);
      put_block(address);
      
      break; 
       
//----------------------------------------------------------
// Arithmetic Group      
      
      case '+':
      x = x+y;
      break;
      
      case '-':
      x = x-y;
      break;
      
      case '*':
      x = x*y;
      break;
      
      case '/':
      x = x/y;
      break;
      
      case '%':
      x = x%y;
      break;
      
      case 'x':
      x = x + 1;
      break;
      
      case 'y':
      y = y + 1;
      break;
     
//--------------------------------------------------------------------
// Logical Group - provides bitwise logical function between x and y

      case '&':
      x = x&y;                             // Logical AND
      break;
      
      case '|':
      x = x|y;                             // Logical OR
      break;
      
      case '^':
      x = x^y;                             // Logical XOR
      break;
      
      case '~':
      x = !x;                              // Complement x
      break;
      
      case ' ':                            // Transfer x into second variable y
      k=y;                                 // Transfer loop counter into k 
      y= x;
      break;
      
      case '#':                            // Load x with the ASCII value of the next character  i.e. 5 = 35H or 53 decimal  
      x=*(buf-2);
      break; 

      case '$':                            // print out a number as either a 2 digit or 4 digit Hexadecimal
      if(x<=255) {hex_print_2(x); break;}
      hex_print_4(x);
      break;

// ----------------------------------------------------------------------      
// Memory Group 

      case '!':     // store
      y = x;
      break;
      
      case '@':     // Fetch
      x = y;
      break;

/*
      case 'r':                         // read a byte from RAM
      bite = bufRead(x);                // x = address
      x = bite;
      uart_putc(x);                     // print the character
      break;
      
      case 'q':                         // read a block of x bytes of RAM at address y     
      for (int i=0; i<x; i++) {
      bite = bufRead(y+i);              // read the array
      uart_putc(bite);                  // print the character to the serial port
      }
      break;
      
      
      case 'w':                         // write a byte to RAM  address in y, data in x
      bufWrite(y,x);
      break;

*/

//--------------------------------------------------------------------
// Comparison Test and conditional Group
     
      case '<':
      if(x<y){x=1;}              // If x<y x= 1 - can be combined with jump j
      else x=0;
      break;
      
      case '>':
      if(x>y){x=1;}              // If x>y x= 1 - can be combined with jump j
      else x=0;
      break;
      
      case 'j':                  // test  if x = 1 and jump next instruction    
      if(x==1){*buf++;}    
      break;

//----------------------------------------------------------------------------------
// Print out the current word list
      
      case '?':                             // Print out all the RAM
      parray = &array[0][0];                // reset parray to the pointer to the first element 
      
      for (int j = 0; j<26; j++) {
      
      uart_putc(j+65);                  // print the caps word name
      uart_putc(32);                    // space
        
      for (int i=0; i<len; i++) {
      in_byte = bufRead( parray +  (j *len )+i);          // read the array
      uart_putc(in_byte);                                 // print the character to the serial port
    }
    
     crlf();
   
   }  
   for(int i = 0; i <11; i++)      // add some spaces to make it more legible on the page
  
   {       
   crlf();
   }  
    break;
//----------------------------------------------------------------------------------------------------
// Conditional Code branch

    case '[':                                     // The start of a condition test
      k = x;
      start = buf;                               // remember the start position of the test
      while ((ch = *buf++) && ch != ']') {       // get the next character into ch and increment the buffer pointer *buf - evaluate the code
      } 
     
     case ']':
    if (x) {                                    // if x is positive - go around again
     buf = start;
    }    
      break; 
            
//-------------------------------------------------------------------------- 
// Case Statement Selection
// Select some code from a list separated by commas

//5(0p,1p,2p,3p,4p,5p,6p)  should select 5 and print it

case '(':

      k = x;                                                 // copy x to use as the "phrase counter"                                                                
                                                             // decrement k to see whether to interpret or not
      while (k)
      {
      ch = *buf++;
      if (ch == ',')
      { k--;}      
      }     
      break;
      
      case ',':
      
      k--;                                              // 
      while (k<0)                                       // k < 0 so skip the remaining entries in the list 
      {
      ch = *buf++;                                      // skip the remaining characters 
      if (ch == ')') {break;} 
      }
      
      break;
//-----------------------------------------------------------------------------------------------------------------------------------------------       
// Analogue and Digital Input and Output Group   - these add heavily to total - need to be converted to MSP430 

      case 's':
//      x = ADC_Read();         // Adds 38 bytes
      break;

 /* 
      case 'a':   
      analogWrite(d,x);           // adds 340 bytes
      break;
      
     

      case 'i':
      x = digitalRead(d);        // adds 100 bytes
      break;
     
      case 'o':
      digitalWrite(d, x%2);     // adds 18 bytes
      break;
 */

//-------------------------------------------------------------------
// Delays Group

    case 'm':
    delay(x<<4);
    break;
      
    case 'u':
    delayMicroseconds(x<<4);
    break;    
//---------------------------------------------------------------------      
      
    case '{':
      k = x;
      loop = buf;
      while ((ch = *buf++) && ch != '}') {
      }
    case '}':
      if (k) {
        k--;
        buf = loop;
      }
      break;
      
      
    case 'k':
      x = k;
      break;
           
// -----------------------------------------------------------------------------
// Launchpad LED group  support for red and green LEDs on entry level LaunchPad
      
      case 'w':
 {
 P1OUT |= BIT0;
 }
 break;
 
 case 'r':
 {
 P1OUT &= ~BIT0;
 }
 break;
 
 case 'h':
 {
 P1OUT |= BIT6;
 }
 break;
 
 case 'l':
 {
 P1OUT &= ~BIT6;
 }
 break;

// ----------------------------------------------------------------------      
      
    }
  }
}

//-----------------------------------------------------------------------------
// SPI RAM Extensions to SIMPL   Test routines etc
//---------------------------------------------------------------------

char RAM_stream_mode()
{
  
    ssDeselect;
    delay_1ms;
    
        uint8_t chipMode;
       
        chipMode = SR_getMode();    // check status register for sequential mode
        if (chipMode != 0x41) {
            SR_setMode(0x41);
             return 0;
        }       
        return 1;
       }        
//---------------------------------------------------------------------------
// Check that the external RAM is present and that it is in Sequential Mode
int spi_check()

{
        ssDeselect;
        delay_1ms;   
        uint8_t chipMode;

        // make sure there is a 23K256 chip and that
        // is wired properly and in sequential mode
        
        chipMode = SR_getMode();
        if (chipMode != 0x41)
        {
            SR_setMode(0x41);
            uart_puts((char *)"SPI RAM not found\n\r"); 
        }
        else
        {
        uart_puts((char *)"32K SPI RAM Connected!\n\r"); 
        }
}

//--------------------------------------------------------------------------
// RAM mode
// Where mode = 
// 0x01  Byte Mode
// 0x81  Page Mode           (Page = 32 bytes)
// 0x41  Sequential Mode
//--------------------------------------------------------------------------

char RAM_byte_mode(char mode)          // Set the RAM into the correct mode
{
        ssDeselect;
        uint8_t chipMode;
       
        chipMode = SR_getMode();       // check status register for byte mode
        if (chipMode != mode) {
        SR_setMode(mode);
        return 0;
        }       
        return 1;
}        

// -----------------------------------------------------------------------------
//spi_fill()- fill the RAM from address with "initial orders"  characters
// -----------------------------------------------------------------------------

void spi_fill(int address, int length )                 // fill
{
    uint16_t i;
    char storedValue = 0;
    RAM_stream_mode();
    SR_writestream(address);                                 // start writing at address
    
    for(j=0; j<6; j++)
    {
    for (i = 0; i < 32; ++i) 
    {
    storedValue = int (array[j][i]);
    RWData(storedValue);
    }
    }
  
} 

//-----------------------------------------------------------------------------------------

void put_block(int address)
{  
  
    uint16_t i;
    char storedValue = 0;
    RAM_stream_mode();
    SR_writestream(address*32);                                 // start writing at address
    
    for (i = 0; i < 32; ++i) 
    {
    storedValue = int (buf[i]);                              // copy key buffer to RAM block 
    if(storedValue != 92)                                   // omit opening \ and closing \                                     
    {
    RWData(storedValue);
    uart_putc(storedValue);
    }
    }
   
   
// -----------------------------------------------------------------------------
// dump the characters from RAM to screen - putting a newline every 64 bytes
// -----------------------------------------------------------------------------

void dump(int address, int length)

{
  int i =0;
  
     crlf();                         // Start with a newline!
     
    RAM_stream_mode();
    SR_readstream(address); // start reading at address 0
    for (i = 0; i < length ; ++i)
   
       {
       if(i%32 == 0)
       {  
         crlf();                       // put a newline every 32 chars 
         
         printlong(i+ address);                          // print the line address followed by four spaces
         uart_putc(0x20);
         uart_putc(0x20);
         uart_putc(0x20);
         uart_putc(0x20);        
       } 
               
       RAM_byte = RWData(DUMMY_BYTE); 
       if(RAM_byte <= 31) {RAM_byte =  '.';}      // Make it a full stop for unprintable characters       
       uart_putc(RAM_byte);                 
}

}

//--------------------------------------------------------------------------------------------
// Generate a familiar hex dump of the RAM area

void hex_dump(int address, int length)

{  
  crlf();                          // Start with a newline!
 
  int i =0;
  SR_readstream(address); // start reading at address 0 

  for (j = address >>5; j <= (address +length)>> 5 ; ++j)
  {
    for (i = 0; i < 32 ; ++i)
       {
       if(i== 0)
       {
         hex_print_4(j<<5);                          // print the line address as HEX  followed by 2 spaces
         uart_putc(0x20);
         uart_putc(0x20);         
       } 
       
       RAM_byte = RWData(DUMMY_BYTE);             // Now read and print the data as numbers
      // printlong(RAM_byte);
       hex_print_2(RAM_byte);
       
       block_array[i] = RAM_byte;                 // block_array is a temporary buffer to hold current RAM block
       uart_putc(0x20);                           // followed by a space
       }
       
       uart_putc(0x20);                            // Separate columns with 3 spaces
       uart_putc(0x20);
       uart_putc(0x20);
            
       for (i = 0; i < 32 ; ++i)          // start reading back at address 0 so as to print the characters
       {      
       RAM_byte = block_array[i];    
       if(RAM_byte <= 31  || RAM_byte >= 127) {RAM_byte =  '.';}      // Print a full stop for all unprintable characters
       uart_putc(RAM_byte);
       }
       
      crlf();                 // put a newline every 32 chars         
  }   
}
//-----------------------------------------------------------------
// Convert a char into a 2 character hex pair

void hex_print_2(int dec_value)
{    
  ha = dec_value >> 4;
  hex_print_char(ha);
  ha = dec_value - (ha << 4);
  hex_print_char(ha); 
} 

//-----------------------------------------------------------------
// Convert an int into into a 4 character hex pair
// note all binary mults and divs should use shift ops for efficiency

void hex_print_4(unsigned int decimal_value)
{   
  int div_value = decimal_value >> 8;
  hex_print_2(div_value);
  dec_value = decimal_value - (ha << 8);   
  hex_print_2(dec_value);
  uart_putc(32);                             // output a space  
} 

void hex_print_char(char hex_value)        //  decode the A-F numbers
{  
  if (ha <=9){hex_char = '0' + ha ;}       // Digits 0-9
  if (ha >= 10) {hex_char = '7' + ha ;}    // Letters A-F
  uart_putc(hex_char);  
}  
//---------------------------------------------------------------------------
// RAM Block routines

void get_block(int address)

{
  int i =0;
   
    RAM_stream_mode();
    SR_readstream(address << 5); // start reading at address 
    for (i = 0; i <32 ; ++i)
     {
       RAM_byte = RWData(DUMMY_BYTE); 
       block_array[i] = RAM_byte;                 // block_array is a temporary buffer to hold current RAM block    
//       uart_putc(RAM_byte);
        
     } 
//      crlf();     
}


//---------------------------------------------------------------------------------------------
void execute_block(int address)                   // Load a block and execute it
{ 
  get_block(address);
  run_block();
}

//---------------------------------------------------------------------------------------------
// Point the Interpreter at the code contained in block_array and let it execute it!
void run_block()

{  
  textEval(px_array);            // Evaluate and execute the User's expression fo External RAM  
}  
//---------------------------------That's All Folks---------------------------------------------



void LCD_print_4133(void)

{
  
   // Configure LCD pins
    SYSCFG2 |= LCDPCTL;                                        // R13/R23/R33/LCDCAP0/LCDCAP1 pins selected

    LCDPCTL0 = 0xFFFF;
    LCDPCTL1 = 0x07FF;
    LCDPCTL2 = 0x00F0;                                         // L0~L26 & L36~L39 pins selected

    LCDCTL0 = LCDSSEL_0 | LCDDIV_7;                            // flcd ref freq is xtclk

    // LCD Operation - Mode 3, internal 3.08v, charge pump 256Hz
    LCDVCTL = LCDCPEN | LCDREFEN | VLCD_6 | (LCDCPFSEL0 | LCDCPFSEL1 | LCDCPFSEL2 | LCDCPFSEL3);

    LCDMEMCTL |= LCDCLRM;                                      // Clear LCD memory

    LCDCSSEL0 = 0x000F;                                        // Configure COMs and SEGs
    LCDCSSEL1 = 0x0000;                                        // L0, L1, L2, L3: COM pins
    LCDCSSEL2 = 0x0000;

    LCDM0 = 0x21;                                              // L0 = COM0, L1 = COM1
    LCDM1 = 0x84;                                              // L2 = COM2, L3 = COM3

    // Display "123456"
    LCDMEM[pos1] = digit[1];
    LCDMEM[pos2] = digit[2];
    LCDMEM[pos3] = digit[3];
    LCDMEM[pos4] = digit[4];
    LCDMEM[pos5] = digit[5];
    LCDMEM[pos6] = digit[6];

    LCDCTL0 |= LCD4MUX | LCDON;                                // Turn on LCD, 4-mux selected

    PMMCTL0_H = PMMPW_H;                                       // Open PMM Registers for write
    PMMCTL0_L |= PMMREGOFF_L;                                  // and set PMMREGOFF

//    __bis_SR_register(LPM3_bits | GIE);                        // Enter LPM3.5
//    __no_operation();                                          // For debugger
}


void LCD_display_n(int number)

{
  
  LCDMEMCTL |= LCDCLRM;                                      // Clear LCD memory

    LCDCSSEL0 = 0x000F;                                        // Configure COMs and SEGs
    LCDCSSEL1 = 0x0000;                                        // L0, L1, L2, L3: COM pins
    LCDCSSEL2 = 0x0000;

    LCDM0 = 0x21;                                              // L0 = COM0, L1 = COM1
    LCDM1 = 0x84;                                              // L2 = COM2, L3 = COM3

    // Display "123456"
    int n = number / 100000;
    LCDMEM[pos1] = digit[n];
    n = number - (100000*n);
    n = n/10000;
    LCDMEM[pos2] = digit[n];
    n = number - (10000*n);
    n = n/1000;
    LCDMEM[pos3] = digit[n];
      n = number - (1000*n);
    n = n/100;
    LCDMEM[pos4] = digit[n];
     n = number - (100*n);
    n = n/10;
    LCDMEM[pos5] = digit[n];
     n = number - (10*n);
    
    LCDMEM[pos6] = digit[n];

    LCDCTL0 |= LCD4MUX | LCDON;                                // Turn on LCD, 4-mux selected

}

Share this post


Link to post
Share on other sites

SIMPL  - for the MSP430G2533 Launchpad

 

I realise that quite a few will have the MSP430G2553 Launchpad - so below I am including some code that will allow it to run SIMPL.

 

As a bare minimum, SIMPL needs the uart initialised - so as to allow communication with the pc.

 

You may also wish to initialise P1.0 and P1.6 for the LEDS - so you can see the effect of your commands.

 

 

As SIMPL grew out of Txtzyme, and was originally for Arduino, it made full use of the following Arduino wiring functions:

 

Serial.begin

Serial.print

digitalRead

digitalWrite

analogRead

analogWrite   (pwm)

millis()

micros()

delay

delayMicroseconds

 

However, if you are familiar with Arduino, these functions tend to be big and slow, so in SIMPL, I have tried to rewrite them in a bare minimum format - so the code does carry  2000 bytes of unnecessary baggage.

 

My aim was to get a working version into just 2Kbytes.  The other idea, was to incorporate SIMPL with a serial bootloader - so that the serial functions could be shared, thus keeping the combined size to a minimum.

 

Once the MSP430 has the SIMPL bootloader, you can then start to exercise the peripherals and perform test commands and looped scripts, without having to use anything other than the terminal program.

 

My MSP430G2553 version is on this Github Gist

 

https://gist.github.com/anonymous/034dd41f108263d09803

 

And the code is listed below in the code window.

 

As you can see  - it has grown a bit from the 100 lines of Txtzyme.

 

This version compiles in around 1848 bytes, and it has sufficient RAM for 13 User Defined words (A to M).

 

Examples

 

 

w turns on the Red LED

r  turns off the Red LED

 

h  turns on the Green LED

l   turns off the Green LED

 

m gives a delay of about 1mS

 

So we can combine these into a 10 flashes of the red LED using the loop function {........}

 

10{r100mw100m}

 

We can also print out number sequences

 

10{kp_ Green Bottles_}

 

 

Where k is a loop counter that startes at 10 and decrements by one, each time around the loop.

 

The ? command will allow you to show the current contents of RAM memory. As the '2533 only has 512 bytes of RAM, we are a bit limited, but we can allocate an array of 13 x 32 (416 bytes)  which is enough for a few simple experiments.

 

 

We can now define our own words  - Like a "Hello World" message.

 

We tell the interpreter that we are going to create a definition and store it in RAM.  We do this by typing the colon : followed by the name of the definition in our case H.

 

:H _Hello World Welcome to SIMPL!_

 

On pressing return, this will execute the buffer contents, and then execute the user defined word H

 

If you press ? you will see the new definition listed next to entry H

 

As we like this greeting so much, let's say it 3 times - by forming a new word A

 

:A  HHH

 

and another B

 

:B  30{A}

 

All of a sudden we are over-run by greetings!

 

 

SIMPL can do maths  - up to 32 bits.  + - * / %   and logical  & | ^ ~

 

1000000 1234567+p                          

 

 

The space between the numbers tells the interpreter to shove the first number into another  variable, to make room for the next number

 

 

We can also sample the analogue voltage on P1.3 - and print it out   - say 100 times

 

100{sq}

 

 

 

SIMPL can do a lot more - you just have to experiment a little.

 

 

More notes and tips tomorrow - hopefully some of you will have a try of SIMPL.

 

 

Ken

// SIMPL Interpreter for MSP430 Launchpad  - inspired by an original idea by Ward Cunningham

// Derived from minimal 868 byte Txtzyme Nano Interpreter for MSP430 Launchpad with MSP430G2533

// Add in SIMPL framework - to allow construction and use of user defined words -  increases to 1860 bytes

#define RXD		BIT1    // Receive Data (RXD) at P1.1
#define TXD		BIT2    // Transmit Data (TXD) at P1.2
#define RED   0x20              // Red LED is on Bit 6    
#define GREEN 0x01              // Green LED is on Bit 0

#define bufRead(addr)      (*(unsigned char *)(addr))
#define bufWrite(addr,    (*(unsigned char *)(addr) = ()



      #define bit0 0x01   // 1
      #define bit1 0x02   // 2
      #define bit2 0x04   // 4
      #define bit3 0x08   // 8
      #define bit4 0x10   // 16
      #define bit5 0x20   // 32
      #define bit6 0x40   // 64
      #define bit7 0x80   // 128
   
// This character array is used to hold the User's words

char array[10][32];            // Allocate a storage array in memory

/*
= {                            // Define a 26 x 48 array for the colon definitions
                         {"6d40{h1106ul1106u}"},  // Musical tones A - G
                         {"6d45{h986ul986u}"},
                         {"6d51{h929ul929u}"},
                         {"6d57{h825ul825u}"},
                         {"6d64{h733ul733u}"},
                         {"6d72{h690ul691u}"},
                         {"6d81{h613ul613u}"},
                         {"_Hello World, and welcome to SIMPL_"},
                         {"5{ABC}"},
                         {""},
                         {""},
                         {""},
                         {"_This is a test message - about 48 characters_"}
                         };
                         
*/                         
                        
//    int a = 0;          // integer variables a,b,c,d
//    int b = 0;
//    int c = 0;
//    int d = 6;          // d is used to denote the digital port pin for I/O operations
//    int d =13;          // d is used to denote the digital port pin for I/O operations Pin 13 on Arduino

     char buf[32];
     char num_buf[11];            // long enough to hold a 32 bit long  

    unsigned long x = 0;    // Three gen purpose variables for stack & math operations
    unsigned long y = 0;
    unsigned int  z = 0;
    unsigned int ADC_value=0;

    unsigned char in_byte;
 
    int len = 32;        // the max length of a User word
   
    long old_millis=0;
    long new_millis=0;
    
//    long D_num = 0;
//    long D_val = 0;
//    long D_decade = 0;
        
    char name;    
    char* parray;    
     
    char* addr;
 
    unsigned int num = 0;
    unsigned int num_val = 0;
    int j;
   
    int decade = 0;
    char digit = 0;

  

// unsigned int x = 0;
// int d = 6;

/*

void uart_rx_isr(unsigned char c) {
	uart_putc(c);
	P1OUT ^= BIT0;		// toggle P1.0 (red led)
}


void (*uart_rx_isr_ptr)(unsigned char c);


void uart_set_rx_isr_ptr(void (*isr_ptr)(unsigned char c)) 
{
	uart_rx_isr_ptr = isr_ptr;	
}

*/
//------------------------------------------------------------------------------------
// UART Routines

void uart_init(void)
{
//	uart_set_rx_isr_ptr(0L);

	P1SEL  = RXD + TXD;                       
  	P1SEL2 = RXD + TXD;                       
  	UCA0CTL1 |= UCSSEL_2;                     // SMCLK
  	UCA0BR0 = 104;                             // 1MHz 9600
  	UCA0BR1 = 0;                              // 1MHz 9600
  	UCA0MCTL = UCBRS0;                        // Modulation UCBRSx = 1
  	UCA0CTL1 &= ~UCSWRST;                     // Initialize USCI state machine
//  	IE2 |= UCA0RXIE;                          // Enable USCI_A0 RX interrupt
}

unsigned char uart_getc()
{
    while (!(IFG2&UCA0RXIFG));                // USCI_A0 RX buffer ready?
    return UCA0RXBUF;
}

void uart_putc(unsigned char c)
{
	while (!(IFG2&UCA0TXIFG));              // USCI_A0 TX buffer ready?
  	UCA0TXBUF = c;                          // TX
}




void uart_puts(const char *str)                // Output a string 
{
     while(*str) uart_putc(*str++);
}



// Print a 16 bit int number 

  static void printlong(unsigned long num)
  {
  if (num / (unsigned long)10 != 0) printlong(num / (unsigned long)10);
  uart_putc((char)(num % (unsigned long)10) + '0');   
  return;
  }
  
  
  // Print a CR-LF

  void crlf(void)                  // send a crlf 
  {  
  uart_putc(10);
//  uart_putc(13); 
  }
  
  
//-------------------------------------------------------------------------------------
// ADC Configuration

void ConfigureAdc(void)
{
 
	ADC10CTL1 = INCH_3 + ADC10DIV_3 ;         // Channel 3, ADC10CLK/3
	ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;  // Vcc & Vss as reference, Sample and hold for 64 Clock cycles, ADC on, ADC interrupt enable
	ADC10AE0 |= BIT3;                         // ADC input enable P1.3
}


 int ADC_Read(void)
 
 {
   
   ADC10CTL0 |= ENC + ADC10SC;			// Sampling and conversion start
   // __bis_SR_register(CPUOFF + GIE);	// Low Power Mode 0 with interrupts enabled
   
   
   ADC_value = ADC10MEM;
   
   return ADC_value;
   
 } 

//-------------------------------------------------------------------------------------

void delay_mS(int j){
    volatile unsigned long i;
   
           while(j)
{           
           i = 42;             	         // Delay
   	   do (i--);	 
           while (i != 0);	        // busy waiting (bad)
           j--;
}	  
}


/*

interrupt(USCIAB0RX_VECTOR) USCI0RX_ISR(void)
{
	if(uart_rx_isr_ptr != 0L) {
		(uart_rx_isr_ptr)(UCA0RXBUF);
	}
}

*/

int main(void)
{
        WDTCTL  = WDTPW + WDTHOLD; 	// Stop WDT
	BCSCTL1 = CALBC1_1MHZ;          // Set DCO
  	DCOCTL  = CALDCO_1MHZ; 
	P1DIR  = BIT0 + BIT6; 		// P1.0 and P1.6 are the red+green LEDs	
	P1OUT  = BIT0 + BIT6; 		// All LEDs off

        uart_init();                    // Initialise the UART for 96000 baud
        
        
        P1SEL |= BIT3;	                // ADC input pin P1.3
        ConfigureAdc();		
        
        parray = &array[0][0];          // parray is the pointer to the first element 
//-------------------------------------------------------------------------------    


//  pinMode(d,OUTPUT);
	// register ISR called when data was received
//    uart_set_rx_isr_ptr(uart_rx_isr);

//    __bis_SR_register(GIE);

//   uart_puts((char *)"MSP430 SIMPL\n\r");    // send banner message

  while(1)
  {     
                
  txtRead(buf, 64);      // This is the endless while loop which implements the interpreter - just 3 simple functions
  txtChk(buf);           // check if it is a : character for beginning a colon definition   
  txtEval(buf);
  } 
  
}    // End of main

void txtRead (char *p, byte n) {
  byte i = 0;
  while (i < (n-1)) {
    char ch = uart_getc();
    if (ch == '\r' || ch == '\n') break;
    if (ch >= ' ' && ch <= '~') {
      *p++ = ch;
      i++;
    }
  }
  *p = 0;
}



// --------------------------------------------------------------------------------------------------------- 
void txtChk (char *buf)       // Check if the text starts with a colon and if so store in temp[]
{       
  if (*buf == ':')  {  
  char ch;
  int i =0;
  while ((ch = *buf++)){
    
  if (ch == ':') {
  uart_putc(*buf);   // get the name from the first character
  uart_putc(10);
  uart_putc(13);
  name = *buf ;
  buf++;
  }
 
  bufWrite((parray + (len*(name-65) +i)),*buf);
   
  i++;
 
}

 x = 1;
 
} 
}



void txtEval (char *buf) {
  
//  unsigned int k = 0; 
  char *loop;
  char *start;
  char ch;
  
  unsigned long k = 0;
 
   
  
  
  
  while ((ch = *buf++)) {
    switch (ch) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      x = ch - '0';
      while (*buf >= '0' && *buf <= '9') {
        x = x*10 + (*buf++ - '0');
      }
      break;
      
//-------------------------------------------------------------------------------     
 // User Words     
      
      case 'A':            // Point the interpreter to the array containing the words
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':
      case 'I':
      case 'J':
      case 'K':
      case 'L':
      case 'M':
      case 'N':
      case 'O':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
      case 'T':
      case 'U':
      case 'V':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
  
 //     name = ch - 65;
      addr = parray + (len*(ch-65));
      
      txtEval(addr);
      break;
     
//---------------------------------------------------------------------------------    
//  Primitive and User vocabulary defined in this section      

      
 
      
// Timing & Printing Group

      case 'p':
      printlong(x);
      break;

      case 'q':              // print integer with crlf
      printlong(x);
      crlf();
      break;
            
      case 'b':
 //     printlong(millis());
      crlf();
      break;
      
      case 'c':
//      printlong(micros());
      crlf();
      break;
      
      case 'd':
//      d = x;
      break;
      
      
        
    case '_':                                             // Print the string encloseed between underscores _Hello_
      while ((ch = *buf++) && ch != '_') {
        uart_putc(ch);
      }
      uart_putc(10);
      break; 
      

      
//----------------------------------------------------------
// Arithmetic Group      
      
      case '+':
      x = x+y;
      break;
      
      case '-':
      x = x-y;
      break;
      
      case '*':
      x = x*y;
      break;
      
      case '/':
      x = x/y;
      break;
      
      case '%':
      x = x%y;
      break;
      
      case 'x':
      x = x + 1;
      break;
      
      case 'y':
      y = y + 1;
      break;
      
      case ' ':                            // Transfer x into second variable y
      k=y;                                 // Transfer loop counter into k 
      y= x;                                // So we can do maths on 2 operands!
      break;
     
//--------------------------------------------------------------------
// Logical Group - provides bitwise logical function between x and y

      case '&':
      x = x&y;             // Logical AND
      break;
      
      case '|':
      x = x|y;             // Logical OR
      break;
      
      case '^':
      x = x^y;             // Logical XOR
      break;
      
      case '~':
      x = !x;              // Complement x
      break;

// ----------------------------------------------------------------------      
// Memory Group 

      case '!':     // store
      y = x;
      break;
      
      case '@':     // Fetch
      x = y;
      break;

/*


      case 'r':                  // read a byte from RAM
      bite = bufRead(x);         // x = address
      x = bite;
      uart_putc(x);          // print the character
      break;
      
      case 'q':                    // read a block of x bytes of RAM at address y     
      for (int i=0; i<x; i++) {
      bite = bufRead(y+i);          // read the array
      uart_putc(bite);                           // print the character to the serial port
      }
      break;
      
      
      case 'w':                  // write a byte to RAM  address in y, data in x
      bufWrite(y,x);
      break;

*/

//--------------------------------------------------------------------
// Comparison Test and conditional Group
     
      case '<':
      if(x<y){x=1;}      // If x<y x= 1 - can be combined with jump j
      else x=0;
      break;
      
      case '>':
      if(x>y){x=1;}      // If x>y x= 1 - can be combined with jump j
      else x=0;
      break;
      
      case 'j':                  // test  if x = 1 and jump next instruction    
      if(x==1){*buf++;}    
      break;

//----------------------------------------------------------------------------------



// Print out the current word list
      
      case '?':                             // Print out all the RAM
      parray = &array[0][0];                // reset parray to the pointer to the first element 
      
      for (int j = 0; j<26; j++) {
      
      uart_putc(j+65);                  // print the caps word name
      uart_putc(32);                    // space
        
      for (int i=0; i<len; i++) {
      in_byte = bufRead( parray +  (j *len )+i);          // read the array
      uart_putc(in_byte);                                 // print the character to the serial port
    }
    
     crlf();
   
   }  
   for(int i = 0; i <11; i++)      // add some spaces to make it more legible on the page
  
   {       
   crlf();
   }  
    break;
 


//----------------------------------------------------------------------------------------------------
// Conditional Code branch

    case '[':                                     // The start of a condition test
      k = x;
      start = buf;                               // remember the start position of the test
      while ((ch = *buf++) && ch != ']') {       // get the next character into ch and increment the buffer pointer *buf - evaluate the code
      } 
     
     case ']':
    if (x) {                                    // if x is positive - go around again
     buf = start;
    }    
      break; 
      
     
      
//-------------------------------------------------------------------------- 
// Case Statement Selection
// Select some code from a list separated by commas

//5(0p,1p,2p,3p,4p,5p,6p)  should select 5 and print it

case '(':

      k = x;                                                 // copy x to use as the "phrase counter"                                                                
                                                             // decrement k to see whether to interpret or not
      while (k)
      {
      ch = *buf++;
      if (ch == ',')
      { k--;}      
      }     
      break;
      
      case ',':
      
      k--;                                              // 
      while (k<0)                                       // k < 0 so skip the remaining entries in the list 
      {
      ch = *buf++;                                      // skip the remaining characters 
      if (ch == ')') {break;} 
      }
      
      break;


//-----------------------------------------------------------------------------------------------------------------------------------------------       
// Analogue and Digital Input and Output Group   - these add heavily to total - need to be converted to MSP430 

      case 's':
      x = ADC_Read();         // Adds 38 bytes
      break;

 /* 
      case 'a':   
      analogWrite(d,x);           // adds 340 bytes
      break;
      
     

      case 'i':
      x = digitalRead(d);        // adds 100 bytes
      break;
     
      case 'o':
      digitalWrite(d, x%2);     // adds 18 bytes
      break;
 */

//-------------------------------------------------------------------
// Delays Group

    case 'm':
      delay_mS(x);
      break;
      
    case 'u':
//      delayMicroseconds(x);
      break;
      
//---------------------------------------------------------------------      
      
    case '{':
      k = x;
      loop = buf;
      while ((ch = *buf++) && ch != '}') {
      }
    case '}':
      if (k) {
        k--;
        buf = loop;
      }
      break;
      
      
    case 'k':
      x = k;
      break;
      
   
      
// ----------------------------------------------------------------------
// Launchpad LED group
      
      case 'w':
 {
 P1OUT |= BIT0;
 }
 break;
 
 case 'r':
 {
 P1OUT &= ~BIT0;
 }
 break;
 
 case 'h':
 {
 P1OUT |= BIT6;
 }
 break;
 
 
 case 'l':
 {
 P1OUT &= ~BIT6;
 }
 break;

// ----------------------------------------------------------------------      
      
    }
  }
}

Share this post


Link to post
Share on other sites

I have been browsing the new MSP430 products.

 

The MSP430FR2xxx range look very interesting as small FRAM based devices.

 

 

For SIMPL the MSP430FR2433 looks the favourite.

 

With 4kBytes of RAM and 15.5kBytes of FRAM  - that gives a substantial workspace for SIMPL 

 

The tiny 4mm x 4mm QFN  would even fit onto a 20 pin DIL carrier board - if mounted at 45 degree orientation - so that it could be plugged into a 'G2553 socket on Launchpad.

 

Almost the equivalent of a early 1980's home computer in a 4mm square package!

 

 

 

Ken

Share this post


Link to post
Share on other sites

I know the FET in the G2 LaunchPad was limited to what microcontrollers you could program with it - i.e. the "value line" topping out at the G2955. I don't know if this has changed with the introduction of more powerful LaunchPads. Anyway, I wouldn't assume that a FR2433 would work in the DIP socket of the G2. 

Share this post


Link to post
Share on other sites

Fred,

 

Thanks for that.

 

In my implementation of this module I have included a uart based  BSL programmer.

 

This will allow programming at least.  

 

 

 

Ken

Share this post


Link to post
Share on other sites

Jazz,

 

Thanks for that useful update.

 

My FR2433 samples have arrived from the USA in record time, and I am now just awaiting the pcbs for the 20 pin module.

 

I am planning two sizes of module, a 20 pin 0.3" DIL and a 40 Pin 0.6" DIL.   The larger of which will support either 16K or 64K of FRAM:

 

F 20-16      20 pin, 16K FRAM   - uses MSP430FR2433  (or FR25xx, FR26xx)

F 40-16      40 pin, 16K FRAM  - Uses MSP430FR5739 or equiv.

F 40-64      40 pin, 64K FRAM  - Uses MSP430FR58xx or FR59xx.

 

All modules have an 8 pin SPI memory footprint. This allows either a 23K256 (32Kx8) or 23LC1024  (128Kx8) SRAM  or any of the Cypress or Fujitsu FRAM parts up to the 256Kx8 to be fitted - depending on budget.

 

The F20 is intended to plug in as a replacement for the G2553.   The F40 is designed to have the same pin out as an ATmega1284 - this is so it can be plugged into various ATmega boards - for an immediate x4 boost in performance.

 

 

Ken

Share this post


Link to post
Share on other sites

I now have a tiny MSP430  module ready for a port of my tiny language.

 

IIn preparation for my own ChipStick pcbs arriving next week, I have soldered the tiny 4x4mm QFN package onto a prototyping module, so that it can be used with a breadboard.

 

I have now managed to get "Blinky" running on the MSP430FR2433.

 

Noting Fred's point above about differences between value line FET programmers,  I hijacked the FET from a MSP430FR4133 Launchpad - as the programming of the FR2xxx series is very similar to that of the FR4xxx series.

 

I then removed the 4 jumpers from the programming section making SBWTDIO, SBWTCK, 0V and 3V3 available and wired these across to pins 1,2, 23 & 24 respectively.  Note that the '2433 has an additional DVSS pin on pin 18 - so this has to be jumpered across to pin 23 so that DVSS gets to both pins.

 

Using CCS V6 to write a blinky test program, on detecting the '2433 device the FET programmer requested a firmware upgrade, but then continued on to program the device as normal.

 

I am quite close to having this module work with Energia - it's just twi.c that barfs at not having certain registers / bits declared - should be a relatively simple fix for those that know where to look in Energia.

 

The details and some photos are included in my latest blogpost. http://sustburbia.blogspot.co.uk/2016/03/building-5-forth-computer-first-steps.html

 

 

 

Ken

Share this post


Link to post
Share on other sites
Noting Fred's point above about differences between value line FET programmers,  I hijacked the FET from a MSP430FR4133 Launchpad - as the programming of the FR2xxx series is very similar to that of the FR4xxx series.

 

All FR devices have the same SBW interface. There is no difference, like on flash 2xx / 5xx familly.

 

For BSL can be used BSL_Scripter in combination with G2 LP. I tested it with FR5739 and FR5949. http://forum.43oh.com/topic/2972-sbw-msp430f550x-based-programmer/?p=43889

Share this post


Link to post
Share on other sites

post-48241-0-66546100-1458313540_thumb.jpg

 

I have wired up the 23K256 SPI SRAM to the MSP430FR2433 module so that it can now execute SIMPL code from the external RAM  - SIMPLEX

 

I have ported the SIMPL code from Energia across to CCS - so that I can now single step with the debugger and see how the code works.

 

I have a bit more debugging to do - but basically a useful breadboardable computer in 2 ICs.

 

The SPI RAM connects to UCSI B0  leaving the PC Comms UART on UCSI A0 and a spare interface on UCSI A1.

 

It might be possible to use the RAM as a  1-bit video RAM - and generate a horizontal and vertical sync signals from the RAM_CS signal and another port line running as a field sync.  This could then push a monochrome image to a VGA monitor with almost no extra hardware.

 

PS/2 keyboard, mouse and Wii - Nunchuck controller (on I2C bus) are definite expansion possibilities.

 

I now need to get the serial  BSL loader working - either using the G2 Launchpad as Jazz has suggested  or possibly this BSL utility from "Kurt"  http://kurt.on.ufanet.ru/  which I have used before successfully on other MSP430 varieties.  

 

I have heard from the PCB factory that my ChipStick pcbs will be shipped early next week.

 

post-48241-0-69311000-1458314186_thumb.jpg

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×