Wednesday, May 26, 2010

Using SPI on Low-End Microcontroller

SPI is a simple and efficient inter-IC communication bus. A lot of peripheral chips such as Real Time Clock and EEPROM come with SPI or I2C bus. If there is no special reason, I prefer to use SPI than I2C because it is faster and simpler. It is also very easy to emulate in software.

Last time, I used 10MHz SPI LED driver chip with low end 4MHz microcontroller. Design priority was cost efficiency. Microcontroller cost less than a dollar but it had enough flash to store the firmware and a few display fonts. At first, I used interrupt and circular buffers to send and receive to and from SPI bus. I just wrote to the buffer and let the hardware and interrupt handled all the communication tasks as I usually do with slower long distance buses such as RS232 and CAN bus. It was OK in normal condition. The problem was that I wanted to update big 96x16 dot-matrix LED at the frame rate of 125Hz and the CPU utilization was very high. Consequently, it could not perform fast enough when it was executing some simple graphic manipulation tasks such as scrolling the text. Later, I realized that the most used SPI function where CPU spent most of its time was not efficient. Using hardware interrupt is more efficient normally, but it was different in this case- slow CPU with very fast and heavily used SPI. For each byte to SPI, send and receive interrupt functions which cost a lot of CPU cycles had to be performed. I found polling or emulation is faster than using interrupt to send a byte to SPI. Polling is still limited to the bus speeds supported by the hardware. After I modified the firmware to improve SPI function and it worked well. According to my experience, let me highlight some advantages of emulating SPI .
  1. It can sometimes be better in performance to emulate SPI in software.
  2. It is more reliable because it is simpler and it can avoid potential pitfalls of using interrupt.
  3. It is faster, easier and less error prone to write a simple code rather than reading datasheet for variety of register settings for every new microcontroller you encountered.
  4. Most importantly, it is portable and it is not dependent on hardware.
SPI does not have formal standard. It is just like a shift register. One can easily understand once s/he sees the timing diagram. The following is an example C function to send and receive a byte of SPI data.
//-------------------------------------
unsigned char spi(unsigned char d)
{
    unsigned char i;
    SCLK=1;
    EN=1;
    for(i=0;i<8;i++)
    {
        MOSI=(d & 0x80)?1:0;        
        //Delay(period/2)-optional for slower SPI bus speed
        SCLK=0;
        d<<=1;        
        d|=MISO;
        //Delay(period/2)-optional for slower SPI bus speed
        SCLK=1;
    }
    EN=0;
    return d;
}
//-------------------------------------

Monday, May 24, 2010

Astable Multivibrator using Op-amp

One of my friends wanted to calculate the oscillation frequency of an op-amp circuit. He had measured the output frequency of the circuit and it was 109 kHz. He asked my help to derive the relation between the oscillation frequency and its passive components. Although I have been away from analog circuits for a long time, I agreed to have a look. Then, he took the picture of circuit diagram using his hand phone and sent to me using MMS.
The basic idea behind the circuit is simple, so I calculated the frequency, took the following pictures using my hand phone and sent back to him.

Saturday, May 1, 2010

Choosing name for our daughter

Here are a few things that we considered when we were choosing a name for our newborn baby. Most of the idea is inspired from the book 'Conception, pregnancy and birth' by Dr. Miriam Stoppard.
  1. We hoped that the name is suitable for her at all stages of life.
  2. We took extra caution not to have any reason why our child might be teased because of the name we've chosen.
  3. We also think that the name should have good meaning.
  4. In case of nationality and traditions, we liked to give her a Myanmar name that follows traditions. For example, to have a first name that matches with the weekday she was born.
  5. We like a name because of its sound. It should be naturally harmonious and sounds good like a sweet music. It should also be read smoothly like a poem.
  6. We like to have one word from father's name and one word from mother's name in the name of our baby.
  7. Although we might be influenced by many considerations, we had to remind ourselves that the name we were choosing was for our baby, and hopefully it will please her throughout the whole of her life.

Wednesday, April 28, 2010

C Programming on Windows

Some of my friends who started learning C programming have asked me which IDE is good to use on Windows. For me, I personally like to use Microsoft Visual Studio Express which is available for free at http:// www.microsoft.com /express/

Dev-C++ from Bloodshed is also a popular one and it can be downloaded from http:// www.bloodshed.net/ devcpp.html.
The following is an example to create new C project on Visual C++ 2008 Express Edition. Go to File menu>>New>>Project... New Project window will appear. Select Win32 in Project types: Visual C++ Select Win32 Console Application in Templates: Visual Studio Installed templates Enter project name in the name text box and browse the folder to save the project. Click OK. Win32 Application Wizard box will appear. Click Next. Choose Console application for Application type and Check Empty project in additional options: Click Finish button. In the Solution Explorer window near the left, right click Source Files and click Add>>New Item... as shown in the following picture. Add new item window will appear. In the Name text box, enter the file name with .c extension e.g. StrPos.c I have been frequently asked how to write a program to find the case insensitive string without using C library functions and the following is an example.
#include <stdio.h>
typedef signed char   CHAR;
typedef signed int    POSITION;
#define ToL(c) (((c)>='A')&&((c)<='Z')?(c+0x20):(c))
POSITION strcmp(CHAR* s1,CHAR* s2)
{ 
    for(;*s2;s1++,s2++) if(ToL(*s1)!=ToL(*s2)) return 0;
    return 1;
}
POSITION stripos (CHAR* haystack,CHAR* needle,POSITION offset)
{        
    for(;*(haystack+offset);offset++) if(strcmp(haystack+offset,needle)) return offset;    
    return -1;  
}
int main(int argc,char *argv[])
{
  CHAR str1[]="Hello! Good morning!";
  CHAR str2[]="good";
  printf("\nFound at: %d \n",stripos(str1,str2,0));   
  return 0;
}
After that, you can run the program by pressing F5 or by clicking Debug menu>>Start Debugging. You can also click Debug menu>>Start Without Debugging.

Tuesday, February 2, 2010

VB2005 Timers

There are several types of timers offered by the .NET Framework. Inside Windows Forms applications, you can use the System.Windows.Forms.Timer control. You can use either the System.Threading.Timer class or the System.Timers.Timer class if your application doesn't have a user interface.
The following is an example that uses the Timer class in the System.Threading namespace to call back a given procedure. After the timer is running, you can change timer values only by means of a Change method, which takes only two arguments, the due time and the period. The Timer object has no Stop method. You stop the timer by calling its Dispose method.
Imports System.Threading
Dim dueTime as New TimeSpan(0,0,1)
Dim period as New TimeSpan(0,0,0,0,500)
Dim t As New Timer(AddressOf TimerProc, Nothing, dueTime, period)
Dim tEn As Boolean = True
Private Sub TimerProc(ByVal state As Object)
 If tEn = True Then
'Do timer things
 End If
End Sub

Friday, December 11, 2009

Protecting Flash Memory of a Fujitsu MCU

I had a requirement to protect flash memory of Fujitsu MB95F128JB MCU but I could not find any satisfactory hardware/software tool to protect it. Later, I conceived an idea to hack its .mhx file. After adding the following line before the last line of the .mhx file, it had been protected.
S104400001BA
Ref: http://en.wikipedia.org/wiki/SREC_%28file_format%29

Saturday, October 10, 2009

Multidrop network for RS232

I got a requirement to communicate one master device and eight slave devices. I intended to use RS485 half-duplex communication for this system but all devices happened to have only RS232 interfaces. RS232 communication is a sort of communication that is to be used for one-to-one system. There is no problem if only the master device transmits and all slaves are receiving. The problem is that transmit lines of the slaves cannot be disabled and so that they cannot connect to the same line. After analyzing the voltage signals, I have got an alternative solution to this problem. By adding a diode to the transmit line of each slave, I can use the system just like RS485 half-duplex communication. See the following figure for the hardware connection.


Updated: 2017 Sep 02
Thanks for all your comments. I have added more configurations according to your comments.

RS232 network with multiple masters and multiple slaves



UART/TTL-Serial network with single master and multiple slaves

If you are not using RS232 transceivers to change the physical signal voltages, the outputs of UARTs are still TTL level signals. In this case, you can connect multiple UARTs to a single master as follow.



UART/TTL-Serial network with multiple masters and multiple slaves



Friday, September 25, 2009

CRC Calculation in VB and C

Just to share a few software modules that were written in Visual Basic 2005 and C for the calculation of CRC -Cyclic Redundancy Check.


CRC Calculation in VB2005

The followings are the source code for various CRC calculations in VB2005. To make the calculation faster, they use CRC tables.


CRC Calculation - GitHub

An example usage for calculation of CRC16 CCITT is shown below.

Dim StrIn as String= "String to calculate CRC"
Dim CRCVal16 As UInt16 = 0
Dim crc As String
CRCVal16 = CRC16_CCITT.Calculate(StrIn)
crc = CRC16_CCITT.ToString(CRCVal16)

Initial value for CRC16 CCITT is 0xFFFF. The following example calculate CRC for Str1 and use that CRC value as initial value to calculate Str2.

CRCVal16 = CRC16_CCITT.Calculate(Str1)
CRCVal16 = CRC16_CCITT.Calculate(Str2, CRCVal16)
crc = CRC16_CCITT.ToString(CRCVal16)

CRC Calculation in C

The followings are the source code for various CRC calculations in C. To save storage, they do not use CRC tables .


CRC Calculation - GitHub

An example usage for calculation of CRC16 CCITT is shown below.

#define STRLEN 4
char str[STRLEN]={0x01,0x01,0x00,0x0B};
unsigned char c[2];
unsigned int crc;
//Calculate CRC16 CCITT
crc=CRC16CCITT_InitialValue();
crc=CRC16CCITT_Calculate(str,STRLEN,crc);
CRC16CCITT_ToString(crc,c);
printf("CRC16 CCITT = %02X %02X \n",c[0],c[1]);


Online checksum calculator such as the following one may be useful to debug the code.

Online Checksum Calculator

Tuesday, August 18, 2009

SDCC - Small Device C Compiler

SDCC - Small Device C Compiler - is a free open source C compiler software for 8051 and a few other microcontrollers. Unlike SDCC, there are other popular commercially available compilers such as Keil that you can purchase. You can download a free evaluation version there but that trial version is limited to 2k byte code size. A good thing about SDCC is that you can get it for free at no cost. This post is just an overview of SDCC manual at http://sdcc.sourceforge.net/doc/sdccman.pdf. Writing and compiling of a few example C programs on Windows for 8051 are  also discussed.


Installing
Go to http://sdcc.sourceforge.net/ and download the setup program Run the setup program and follow the installation process.

Testing the SDCC Compiler
To test the installation of the compiler whether it is OK or not, go to command prompt and enter "sdcc -v". This should return sdcc's version number.

Example C Program
Type in the following example program using your favorite ASCII editor and save as led.c. This is an example C program for 8051 microcontroller to blink an LED connected to P3.4 pin.
#include<8052.h>
void main()
{
int i;
while(1)
{
P3_4=0;   //Output 0
for(i=0;i<30000;i++);  //delay loop
P3_4=1;   //Output 1
for(i=0;i<30000;i++);  //delay loop
}
}


Compiling and Getting Hex File
Go to the path where led.c is located and enter "sdcc led.c". If all goes well the compiler will link with the libraries and produce a led.ihx output file. You can enter "dir" to see if there is led.ihx file. After that, enter "packihx led.ihx>led.hex" to get the intel hex file that is suitable to download into your chip.

Projects with Multiple Source Files
SDCC can compile only ONE file at a time. Let us, for example, assume that you have a project containing the following file: main.c blink.c Type in the following example code in these files.
//File name: main.c
#include "blink.h"
void main()
{
while(1)
{
toggle();
delay();
}
}


//File name: blink.c
#include <8052.h>
#include "blink.h"
void toggle()
{
P3_4^=1;
}
void delay()
{
int i;
for(i=0;i<30000;i++); //delay loop
}


//File name: blink.h
void toggle();
void delay();

The files without main() function will need to be compiled separately with the commands: "sdcc -c blink.c". Then compile the source file containing the main() function and link the files together with the command- "sdcc main.c blink.rel". You will get main.ihx file and then you can get main.hex file as discussed before.

Monday, March 16, 2009

String and ASCII Code Conversion in VB 2005


We have written a customized class for various conversion between ASCII code and string that we need to use occasionally. The source code for the class can be downloaded A Visual Basic class to convert between hexadecimal, ascii, and text string on GitHub.
'Author: Yan Naing Aye
'WebSite: http://cool-emerald.blogspot.sg/
'Updated: 2009 April 24
'-----------------------------------------------------------------------------
Public Class ClsMyStr
    Public Shared Function AsAsciiEncodedStr(ByVal CharString As String) As String
        Dim outS As String = ""
        Dim temp As String = ""
        Dim i As Integer = 0
        For i = 0 To CharString.Length - 1
            temp = "00" & Hex(Asc(CharString(i)))
            temp = Right(temp, 2)
            outS = outS & temp
        Next i
        Return outS
    End Function
    Public Shared Function AsSpacedAsciiEncodedStr(ByVal CharString As String) As String
        Dim outS As String = ""
        Dim temp As String = ""
        Dim i As Integer = 0
        For i = 0 To CharString.Length - 1
            temp = "00" & Hex(Asc(CharString(i)))
            temp = Right(temp, 2)
            outS = outS & temp & " "
        Next i
        Return outS
    End Function
    Public Shared Function AsAsciiDecodedStr(ByVal AsciiEncodedStr As String) As String
        Dim outS As String = ""
        Dim i As Integer = 0
        Dim l As Integer = AsciiEncodedStr.Length - 2

        If (AsciiEncodedStr.Length Mod 2) <> 0 Then
            l -= 1
        End If
        For i = 0 To l Step 2
            outS = outS & Chr(Val("&H" & AsciiEncodedStr.Substring(i, 2)))
        Next i
        Return outS
    End Function
    Public Shared Function GetAsciiEncodedStr(ByVal RawAsciiEncodedStr As String) As String
        Dim i As Integer = 0
        Dim c As String
        Dim cmd As String = ""

        For i = 0 To RawAsciiEncodedStr.Length - 1
            c = RawAsciiEncodedStr(i)
            If (Asc(c) >= &H30) AndAlso (Asc(c) <= &H39) Then
                cmd = cmd & c
            ElseIf (Asc(c) >= &H41) AndAlso (Asc(c) <= &H5A) Then
                cmd = cmd & c
            ElseIf (Asc(c) >= &H61) AndAlso (Asc(c) <= &H7A) Then
                cmd = cmd & Chr(Asc(c) - &H20) 'change to upper case
            Else
                'MessageBox.Show("Got invalid character.")
            End If
        Next i
        If cmd.Length < 2 Then
            cmd = "0" & cmd
        End If
        Return cmd
    End Function
    Public Shared Function DoubleQuote() As String
        Return ControlChars.Quote
    End Function
    Public Shared Function Byte2Text(ByVal byteArray() As Byte) As String
        Dim str As String = BitConverter.ToString(byteArray)
        Return str
    End Function
    Public Shared Function Byte2Str(ByVal byteArray() As Byte) As String
        'Dim str As String = System.Text.Encoding.ASCII.GetString(byteArray)
        Dim str As String = ""
        For i As Integer = 0 To UBound(byteArray)
            str &= Chr(byteArray(i))
        Next
        Return str
    End Function
    Public Shared Function Str2Byte(ByVal str As String) As Byte()
        'Dim ba() As Byte = System.Text.Encoding.ASCII.GetBytes(str)
        Dim ba() As Byte
        Try
            ReDim ba(str.Length - 1)
            For i As Integer = 0 To UBound(ba)
                ba(i) = Asc(str(i))
            Next
        Catch ex As Exception
            ReDim ba(0)
            ba(0) = 0
        End Try        
        Return ba
    End Function
    Public Shared Function GetSignedDecimalText(ByVal RawStr As String) As String
        Dim i As Integer = 0
        Dim c As String
        Dim cmd As String = ""

        For i = 0 To RawStr.Length - 1
            c = RawStr(i)
            If (Asc(c) >= &H30) AndAlso (Asc(c) <= &H39) Then
                cmd = cmd & c
            ElseIf (Asc(c) = &H2D) Then
                If cmd.Length = 0 Then
                    cmd = cmd & c
                End If
            Else
                'MessageBox.Show("Got invalid character.")
            End If
        Next i        
        Return cmd
    End Function
End Class