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.
G2 LP can be used as BSL hardware for FR2xx/4xx www.ti.com/cn/lit/pdf/slaa535
BTW, FR2xx/4xx family has CPUX2, with 20-bit registers, and can execute CPUX2 20-bit address instructions in one cycle. It also has mailbox. Same as FR5xx/6xx.
I'm working on building a speed controller for a belt grinder and I'm using a G2553 for the controller. Since the speed of the motor will need to vary between 1000-8000 RPM, the 32.768Khz clock was too slow and the DCO was drifting too much and causing the RPM to vary by several hundred counts even when the motor was running at a constant stable speed. This in turn caused the PID loop to act really weird and I could not hold a stable speed. What I needed was a stable reference oscillator to use for sensing the RPM of the drive motor.
Being stubborn, I wanted to do this with only a single G2553 cpu and since the 2553 isn't spec'd to use a high freq crystal I went looking for an alternate way to provide a reference for the timers. I was quite happy to discover that P1.0 can be configured as an input for an external timer reference. Thus the "Launchpad Timer Reference Oscillator" was born.
In my application I'm using a 16MHz oscillator, but any speed could be used to fit the given application.
It is a small 0.3" x 1" pcb with an Abracon oscillator, a 0.1uF cap., and connectors.
It only took a minor code change to have the Timer use the external reference and so far it seems to have resolved my timing issues.
While this is without a doubt the most simple PCB I think I have ever designed, it just may turn out to be one of the most useful.
I will definitely be including an external reference oscillator in any of my future projects that need very accurate time references.
About a year or so ago, I quit working on a project which would generate the 1200 baud audio tones for an AFSK Amateur Radio system.
Due to real life getting in the way, I never finished it. I got it to generate the audio tones but never fully implemented the ascii data input handling.
This general design isn't anything new, it has been done before on other platforms and it is quite likely someone has done it on the MSP.
It was my first real development effort using Timers and was a good learning experience.
I figured it was time to post the code in case all or part of it might be useful to someone. USE AT YOUR OWN RISK.
Essentially this code implements a software driven class D amplifier using an MSP430G2553 to generate either a 1200Hz or 2200 Hz sine wave using PWM.
The PWM output is run through a simple low pass filter to get the clean sine wave audio tones.
This uses all of the available timers on the G2553.
TA1 is the PWM generator running at 500Khz
TA0 is the modulator.
WDT is used as an interval timer to clock the ascii data into the modulator at 1200 buad (this is where I stopped working)
The TA0 modulator steps through the wave table and updates the TA1 PWM duty cycle setting it to the value in the wave table. TA1CCR1 = SineTable[sinePosition];
This runs in a continuous loop. The rate at which TA0 steps through the table is the MARK and SPACE values. This rotating PWM duty cycle is what generates the 1200Hz or 2200Hz sine wave.
The 500Khz PWM frequency is filtered out by the low pass filter.
The NOT WORKING parts.
Basically I quit shortly after starting on the ASCII input handling. The idea was that the WDT loop would set TA0 to MARK or SPACE depending on the ASCII character to be sent.
I was in the process of trying to implement a FIFO buffer when I stopped developing the code.
I hope someone finds this useful.
-Brian
WARNING: The code you are about to view most likely breaks every known rule for good software design.
It may use magic numbers, variables named X or Y, have little of no care for memory management, or have numerous other or unknown issues.
This was R&D code and I never really meant for it to be seen by anyone other than myself.
I've have several projects with a 5 pin header for the 6 pin FT232 cable since none of the projects use the 6th pin. One time I plugged the header into pins 2-6 of the FT232 cable instead of 1-5 and my launchpad died :S Also, took a while to get my first MCP23S17 I/O expander to work since the datasheet incorrectly lists the RESET pin as an output, not an input.
Float is handled with native hardware FPU instructions for speed. Double is handled in software (not sure if it's capable of using the FPU but I think not). Float would be much faster.
Last week, I introduced a tiny language, called SIMPL, I have been working with for a while. Now I'd like to introduce some hardware - that I hinted upon last week.
ChipStick is possibly one of the smaller dev boards you may encounter - it's intended to plug into a 20 pin DIL socket - which makes it both breadboard and Launchpad friendly.
At it's heart is one of the new MSP430FR2xxx series devices with 15.5kbytes of FRAM and 4Kbytes of RAM.
These controllers come in a tiny 4mm square 24 pin QFN surface mount package, making them a bit awkward to prototype with - so that's why the idea of ChipStick was developed - a small carrier pcb which converts the SMT part into a plug-in DIL 20 package.
ChipStick also comes with its own programmer section - based on the low cost CH340G USB to serial converter IC. This allows communications between the IC and a laptop, and also allows it to be programmed serially using the uart based BSL programming option.
The programming section is detachable - so you can have just the 20 pin DIL module if you want to go extra small.
In this format the board is small enough to fit inside a 2x4 LEGO block!
In addition to the MSP430 there is also 32K x 8 bytes of external SPI SRAM or FRAM (depending on your application). The MSP430FR2xxx series have 3 communication interfaces and the 25xx and 26xx parts have capacitive touch capability too.
One of the aims of ChipStick is to teach electronics and computer science. Whilst it is not the fastest device the external memory allows virtual machines to be investigated and the high speed SPI allows shift registers to be used for extending the I/O - for driving LED arrays or stepper motors or whatever peripheral electronics you wish.
ChipStick may be programmed using Energia, CCS or a high level language such as Forth, including MECRISP, 4E4th or Amforth.
My inspiration came from another small computer, the PDP5 from 53 years ago.
ChipStick offers about the same computing resources as the PDP5, but for $5 not the $50,000 the PDP5 cost in 1963!
The first batch of ChipStick pcbs have been ordered. After Easter I should have something up and running, at which point the EagleCAD files will be made available.
I don't have a FR4133 so can't test the code but try this:
#elif defined(__MSP430FR4133__)
enum CL_TIMER_t
{
CL_TimerA0, // FR4133 P1.5, pin 11 on LaunchPad
CL_TimerA1, // FR4133 P8.2, pin 9 on LaunchPad
};
// clk pin setup for each supported timer
#define CL_TA0CLK_PIN_SETUP { P1DIR &= ~BIT5; P1SEL0 &= ~BIT5; P1SEL1 |= BIT5; }
#define CL_TA1CLK_PIN_SETUP { P8DIR &= ~BIT2; P8SEL0 &= ~BIT2; P8SEL1 |= BIT2; }
Insert it into CounterLib_t.h just before the section at line 72 with the following code
#else
#error 1) This microcontroller is not supported by CounterLib
#endif
If, in my haste, I did this correctly it should work with the examples on Pin 11 of the FR4133. Please report back whether or not this works for you.
I've been around on the forums for awhile now. I really enjoy seeing other peoples projects. Especially how they go about solving problems that I would hove done differently. I think there is great value in that. That's why I try to post about my projects too.
I'm in my final year of my EE degree. And information I've gained from this forum has definitely influenced my thought pattern for the better when approaching new problems.
But also unfortunately there are people who upon seeing the same project will just be thinking of ways they could profit from others work. There might not actually be too many of these people, but it only takes one to make you think about this stuff next time you think of sharing a project, which is a real shame.
I'll continue to share my hobby projects, A factor that stops me posting more is that not all of my projects contain TI micro's so I don't feel it's relevant to post here. For example I'm currently working on a DIY PnP.
I've also noticed alot more students asking for help with their projects. (assessed projects) (sometimes even capstone projects!) And they typically just want the answer, sometimes don't acknowledge users who try to help. This doesn't look good for the forums. But I'm not sure what the solution is.
I got involved with this community essentially knowing nothing about microcontrollers or C/C++ when I retired as an engineering manager with a mechanical background (in Calgary by the way - one of my favorite places). Microcontrollers were just something that caught my interest after viewing a TED video on Arduino. And on average, the quality of the projects and the help / discussion just seemed to be on a higher level on 43oh than with the Arduino crowd.
For me, learning this stuff beyond the superficial on my own outside of a classroom setting and without colleagues is hard. But it has been rewarding and a great experience. And I have learned something from each of you who have posted above. So, my thanks to you.
This is just a hobby for me, and it is unlikely anyone developing a commercial product is going to gain much from my advice . Having said that, I try to give as much as I take. And a good way to learn and hopefully help others has been to read the problems others are having and see if I can solve them. For those who would like to continue getting that kind of help, here are some tips:
Don't abuse the goodwill of 43oh members in the manner described above
Search and make a real effort to solve it yourself first
Post sufficient information for someone to help solve the problem but be as succinct as possible and don't post a 100 lines of code
Use the thanks button when someone helps - really, how much effort does that take? Somebody just spent personal time to help you for free.
When your problem is solved, consider editing your first post and put [sOLVED] in the title, or at least follow up with a post that you finally got it to work and how. The next person with that problem will thank you.
My son-in-law has a masters in EE and is now a patent attorney. I asked him a while back about the practicalities of protecting intellectual property for the small guy or hobbyist. My interpretation of that conversation was that unless you have money and/or time it is difficult. A shame, the result is that you must do something like Spirilis suggests and carefully consider/tier responses, help, and what is revealed.
I appreciate the help past and future, and enjoy hearing about the projects. But, I also understand the sentiments expressed above and don't want to see livelihoods threatened.
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
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
}
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
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
Here's the output:
ebrundic@spock:~/inst$ ./test
key=[cmd], value=[load]
key=[color], value=[red]
key=[bg], value=[blue]
key=[alpha], value=[0.56]
key=[blah], value=[]
key=[wtf], value=[wtf]
The only output that seems odd is the "=wtf" case, since the code took the value and pointed both key and value pointers to the value. A state variable (called no_key here) could protect against this:
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <string.h>
void run_callback(const char *, const char *);
int main(int argc, char *argv[])
{
size_t i;
char text[] = "cmd=load&&&&&&&&&&&&&color=red&bg=blueα=0.56&&blah=&&&&=wtf&&&&";
size_t tlen = strlen(text);
char *key=NULL, *value=NULL;
int no_key = 0;
for (i=0; i < tlen; i++) {
if (text[i] == '&') { // end of key/value pair
text[i] = '\0';
if (key != NULL) {
run_callback(key, value);
}
key = NULL;
value = NULL;
no_key = 0;
continue;
}
if (text[i] == '=') { // end of key, start of value
no_key = 1;
text[i] = '\0';
value = &text[i+1];
continue;
}
if (!no_key && key == NULL) {
key = &text[i];
}
// otherwise do nothing, keep incrementing i
}
// end of string, we might have a loaded key/value pair to process at the very end
if (key != NULL) {
run_callback(key, value);
}
return(0);
}
void run_callback(const char *key, const char *value)
{
if (key == NULL || value == NULL) {
printf("key=ptr[%p], value=ptr[%p]\n", key, value);
} else {
printf("key=[%s], value=[%s]\n", key, value);
}
}
which produces:
key=[cmd], value=[load]
key=[color], value=[red]
key=[bg], value=[blue]
key=[alpha], value=[0.56]
key=[blah], value=[]
Hello All,
If you have been following the upgrade, there was an issue.
Unfortunately I was unable to get the code to format correctly. I'm still working it out with support.
Note that members registered between the 5th and 7th, you will have to register again. There was one post made, but I have that person's email, so I'll get in tough with him.
Hopefully the downgrade went well. If you see any issues, please raise it up immediately.
I've managed a few. Swapping VCC and VSS on my first etched PCB was a good one. I'm glad I'm not the only one who's done that.
I also noticed that a TS430RGC64USB target board that I had supported the F5510 that I was coding for. Great! So I stuck it in and wondered why it didn't work. It turns out that a LQFP48 will fit in a QFN64 socket. It might not fit that well or work, but it goes in.
Amazingly neither of these (and probably worse that I've forgotten) damaged the MSP430.
If those sensors/parts use too much power when idle, you need to switch them off somehow.
If they don't have a power-down command/signal, you have to switch off their VCC. This can be done either with a transistor (a logic-level MOSFET would need slightly less power than a BJT), or directly with a GPIO if the sensor does not need much power.
Please note that some chips do not allow high voltages on their I/O pins when VCC is zero; those might need protection, too.
A summary of changes:
instead of unipolar motor drivers, now I used a bipolar drivers very popular in RepRap projects, here A4988 (or DRV8825)
28byj-48 modified for bipolar
cheap HC-05 for bluetooth SPP
GPS module U-blox NEO-6m
added RTC DS1307 to provide date/time reference even in the first seconds after power-on and 56 of NVRAM bytes
added (optional) humidity and temperature sensor DSTH01
added a I2C socket to connect external temperature sensors to provide information about motors temperatures
added PCF8574 for microstepping configuration of A4988 drivers
added buzzer for audible indication
added output for 12Vdc fan of main mirror - PWM controlled
Nokia 5110 display replaced with a red back-light
As the software is concerned, there were several improvements as well. The most important is that the motors are now driven by an interrupt driven AccelStepper
When powered on, the mount moves to the first alignment star. Then, a user provides the correction vector: star just needs to be positioned in the middle of view in eyepiece. First star roughly corrects the misalignment in telescope orientation w.r.t. the north. Second star helps to correct also the leveling error. Third star would improve alignment even further. I did not (yet) implement any periodic error correction. The whole alignment procedure takes couple of minutes, and requires a user to center stars in an eyepiece with an attached joystick, and confirm with fire button. GPS resolves the time/date and location issue during start-up in unknown location.
There is a couple of similar projects available on the internet. Some of them base on Arduino and PIC performs very basic mount control without math intensive computation implemented in embedded controller. I decided to build my own with the following goals:
ease of use by an inexperienced amateur astronomer (full automatic operation)
precision and resolution of position
last but not least: the price
Final, or better say at the moment, design comprises of the following components:
Stellaris LM4F launchpad central control unit,
two ULN2003 unipolar stepper motor driver chips,
two 28byj-48 stepper motors one moving in azimuth, and in elevation via gear train,
communication module: Bluetooth serial module. It allows sending a coordinate set-point and provides position feedback to Stellarium,
GPS module providing position and precise time reference - PPS gives 1us accuracy,
Nokia 5110 display unit and joystick for standalone operation,
now obsolete mouse (PS/2) modified to provide independent (incremental) position information
Resolution that was reached is a single step of approx. 5". Given the size of Jupiter to range from 30" to 50", this positioning resolution makes the view comfortably stable in standard 60° FOV eyepiece at reasonably high magnification, without the need to adjust AZ/ALT continuously.
During the development I made use of several opensource and projects available online, namely:
AccelStepper for stepper control,
TinyGPS++ for NMEA decoding,
Arduino telescope controller was my inspiration and reference for Taki's matrix method for coordinates transformation,
of course Energia as my IDE
Upon power-up the mount is performing:
homing
acquisition of current location (longitude/latitude) and time via NMEA stream
moves to 3 brightest (most convenient) stars in succession to perform 3 star alignment procedure - they are selected from the list of over 500 stars in built-in catalog (the brightest are used for the alignment, tough),
once aligned the mount is in tracking mode: it tracks the view to counter the apparent movement of objects in the sky,
waiting, either for the user to move to particular object - selected from the library of stars and Messier objects, or
awaits connection via Bluetooth from a PC running Stellarium with a plugin and slews to selected object.
search for the object that should be visible in the eyepiece and display important information on LCD - I compiled in 500 brightest stars from HYGXYZ and full Messier catalog.
I have very little experience as amateur astronomer so far, so some of the objectives might have been not very obvious for me in the beginning. This project was also a good way to make use of my free time and gain experience in embedded system design.