Friday, March 25, 2016

ADXL335 - Getting started

On the process on learning of pic18f, I like to start with existing code or hardware. So I like modules very much as my pcb design is still in the "room" of improving. I cant get the correct version until the 3rd or 4th version of pcb.

I have this three axis accelerometer breakout, bought from cytron (some time ago). It is the cheapest I can found. Since it is lying on my drawer and I am bored, I decide to test it.


Also, I have a soldering station which I bought from taobao 2 months ago, time to put it on test.

First, I align all the pin at the breadboard,

Then, I place the ADXL335 module on top the pin,


After switch on the soldering station, you need to wait until the red led indication on the soldering station went off, then the solder tip temperature is as set temperature. 
I verify it using vc890 multimeter.

My first try, it is really not bad. The soldering station really not bad, perform better than the 10 ringgit soldering iron that sold at jalan pasar. My soldering station only cost me 45 ringgit, really worth the money.

Actually I had tried popular brand of soldering station before like hakko, weller, goot, but I think this kasadi soldering station "soldering" performance is comparable to those top notch. Maybe the question lied on the robustness,  how long will it last before it break down. Last time, my 15 ringgit soldering iron from jalan pasar only been used for a few times, after leave it for few months, end of life.
Also, my lab weller soldering station is really robust, sometimes, we forgot to switch off it, leave it for two days, but it is still working great. 

I didnt dare to put test on the kasadi soldering station robustness, I handle it with cares, you should not expect much from cheap but working equipment.

Back to story, this is the soldered module
After I have finished solder all the pins, I realise that the top three pins are not necessary, just some dummy pads placed, no track connection to any component.

Now to the coding part, just the simple adc would be fine, c18 comes with some library on pic18f peripheral. However, my purpose is learning so I always look at existing code, datasheet, then start writing my own code.

It make the learning easier and your own code really suit your own need.
I go to c18 library file, copy the adc file out and start editing it for my own use.

In the end, I have only two functions 
- void ADC12_Init(void);
- int ADC12_ReadChannel(unsigned char channel);
which make it very convenient to use, but hard to modify settings (you have to edit the source code).
Overall, the settings of adc are quit general and easily applied to most conditions.

I supply the 5V to the ADXL335 module, it has on board regulator that regulate it to 3.3V. You can also supply the 3.3V to the ADXL335 module directly.

I have disassembly the connections so I have no output picture to show your guys. Nevertheless, the program have been tested and it is working fine.

In this program, the displayed value for X, Y, Z axis are adc value, I have no idea on the calibration (how to convert the adc value to angle using limited equipment). Maybe after some time of learning, trying and googling, I will post it up.

The project file is downloadable at link.



OSA rtos - 2nd

After able to run a simple led blinking using OSA rtos, I plan to integrate one display function ( lcd 16x2) and two push button (event triggered).

So I have added one additional task which is taskDisplay(), the main purpose of task display is showing the some simple words and display simple message when push button is pressed.

The OSAcfg.h file remain the same
 //------------------------------------------------------------------------------
// SYSTEM
//------------------------------------------------------------------------------
// Number of tasks that can be active at one time, two tasks for led blinking, one task for display
#define OS_TASKS               3
// Not using any fancy OS function, so "no priority" setting is set
#define OS_DISABLE_PRIORITY    


For the HD44780 driver, it is remain the same as previous tutorial, I didnt include the OS function in the HD44780 source file.
The development board I used directly ground the RW pin of HD44780, so it is only writeable (unable to implement OS_Wait() function).
I have to use the delay function to wait for HD44780 finishes the operation. The longest wait period is 2ms for HD44780 whereas the OS_Timer() interval is set to be 10ms. If I use one tick delay, it will be 10ms. Still reasonable to implement but I am lazy. After wasting 2ms out of 10ms, I still have 8ms which is a lot of time to do other stuffs, not to mention just simple led blinking.


 //------------------------------------------------------------------------------
// TASK DISPLAY header file
//------------------------------------------------------------------------------
#ifndef TASK_DISPLAY_H
#define TASK_DISPLAY_H

#include "hd44780.h"
#include <osa.h>

#define mInitSW1()   {TRISBbits.TRISB0=1;} // initialise the port direction to input
#define mInitSW2()   {TRISBbits.TRISB1=1;} // initialise the port direction to input

#define mSW_1 PORTBbits.RB0 // switch one
#define mSW_2 PORTBbits.RB1 // switch two

void taskDisplay(void);

#endif /* TASK_DISPLAY_H */

 //------------------------------------------------------------------------------
// TASK DISPLAY source file
//------------------------------------------------------------------------------
void taskDisplay(void)
{
mInitSW1();
mInitSW2();

        // initialize the LCD module is time consuming but it doesn't interfere with OS                                      // operation as OS only run the function above the forever loop on first time.                                          // After that, at each interval, it run the function inside forever loop.
        HD44780_Init();

        HD44780_GoToPoint(1,1);
        HD44780_WriteROMString("  - RTOS OSA -  ");
HD44780_GoToPoint(2,1);
        HD44780_WriteROMString("  -Simple Demo- ");

       for (;;) {
  // wait for switch to be pressed, bad implementation as I do not consider                                               // the switch debounce or noise interference.
        OS_Wait(mSW_1==0);

HD44780_GoToPoint(2,1);


         // String written when switch one is pressed, I make it to be 16 characters so                                          // that I dont have to clear any character left at display.
        HD44780_WriteROMString("Button 1 Pressed");  

  OS_Wait(mSW_2==0);
HD44780_GoToPoint(2,1);

         // String written when switch 2 is pressed.
        HD44780_WriteROMString("Button 2 Pressed");  
    }
}



At the main file, create the task mentioned.
 //------------------------------------------------------------------------------
// CREATE TASK
//------------------------------------------------------------------------------
// Priority zero, all task has equal priority
    OS_Task_Create(0, taskLED1);
    OS_Task_Create(0, taskLED2);
    OS_Task_Create(0, taskDisplay);

Here is the output display,

After initialisation,

After switch one is pressed,

The project file is downloaded at link.



Thursday, February 25, 2016

OSA rtos - First try

Task scheduler has been a very convenient way to manage the task flow without having multiple flags  raised at certain time interval. By optimising the timer interrupt on MCU, one can control the task at almost precise timing but as the tasks get complicated and larger, the readability and maintenance effort also significantly increased.

RTOS - real time operating system is the answer to all these hardships. 
Many people are doubt on using rtos on small mcu as the ram consumption is significantly higher and reliability/support of open source rtos has shunt most novice away.

OSA rtos is chosen for this study because it is using the cooperative scheduling and the next running task is chosen based on priority after the task before run to completion. So the ram consumption for each task is fixed and small.

I will be using PIC18f4553 and mplab c18, so the ram is 4 bytes per task which is small. Also, by enable a full rtos function - only 1214 bytes of rom and 16 bytes of ram are needed. It is small scale enough to implement an adequate system on PIC18f.

OSA rtos has stop it's development but it is still worth trying for hobby project. The OSA seem to be very popular among Russian developers and the tutorials are much complete in Russian language compared with English.

After spending much time on reading and trying to implement the OSA rtos on pic18f4553, I make some progress. I was able to make two leds blinking at different rates. It is simple but I will employ different rtos functions later.

At the introduction part, there are certain limitation on compiler that need cautions such as:
For MICROCHIP C18
-You can't use procedural abstraction optimization
-You can't use Stack Model: Multi-bank

It is not a big deal as you are not enjoying these benefits when using the free version of c18.

One thing that shunt people away is the step to step guide to implement the OSA on pic18f and very few tutorials or examples which are using c18 compiler.

So in this tutorial, I will show a step by step guide to compile in c18.
note: I am using pic18f4553, c18 version 3.47 and mplab v8.92.
1. First step is download the OSA. There are several implementation examples in this link.
2. Secondly, create a mplab project folder and copy the whole OSA folder inside the mplab project folder.

3. Add the necessary header file of OSA. 
Only osa.c is suffice but I add in osa.h for ease of troubleshooting. OSAcfg,h is the settings file which can be referred at this document. Although there is a GUI software to choose the OSA settings but it doesn't work on win 7 (or just maybe my computer).

4. Right right at the project name "osa.mcp" and choose Build Options. At the Directories, click on the "include search path" and add in the osa folder in the search path.  

5. Now, go to MPLAB C18 and type in "disable procedural abstraction optimization" -Opa- . 
If "-Opa-" instruction is at the settings there, then just maintain it as it is. (dont change anything).

6. Choose the single bank model at MPLAB C18 -> Memory Model -> Stack Model as shown below

7. To configure the OSAcfg.h, I will be blinking two leds, so OS_TASKS = 2; simple blinking cant show the task priority so OS_DISABLE_PRIORITY. The OS_ENABLE_TTIMERS and OS_ENABLE_TIMER are defined to enable OS_delay function.

8. My blinking task, led1 with 1 second blinking rate; led2 with 2 second blinking rate.

9. The OS tick increase every 10 ms. The timer interrupt setting is as follow (You can refer to my blog on setting the timer interrupt)
10. The main routine is as follow:
Actually, I havent study the OS_EI() function, I suspect that I can skip some redundant code.

11. You can check the task address using the debugger mode. You can check whether the task is switching or not.

Basically that all, this is the simple implementation.
The whole project zip file can be downloaded at here.



Saturday, December 26, 2015

Timer0 interrupt for pic18f

Normal simple program work in an order entity in forever loop, the execution of function is one by one, from start to the end and back to the start again. Although the program is executed in a predictable manner, but the control of function's occurrence is hard in forever loop. For example, several tasks need to be run at different timings, task1 every 10ms, task 2 every 100ms, and task 3 every 1s. A timer is needed to keep track of the program execution and run the task at each time interval.
To enable precise control of tasks, timer needs to work independently from forever loop and interrupt the forever loop at pre-set time interval.

The below tutorial uses two leds to show the tasks execution in 1s and 2s.
Timer0 is used where a 10ms flags is raised at each interrupt. At each 10ms, a counter is increased, when the 1s is reached, led1 will blinks, for the next second, led2 will blinks.

There are three ways to set up the timer0 interrupt which are high interrupt, and low interrupt.
In this tutorial, high interrupt timer0 is shown.

For starter, always read the datasheet but microchip wikidot has prepared a good explanation for developer.

The timer0 register, always refer back when setting the timer0 module.

The basic structure of timer0 is

It can serves as timer or a counter, the timer source is MCU frequency divided by 4 while pin interrupt is T0CK1.

To enter timer mode, register TMR0CS need to be cleared.

Another important register is prescaler

Clear PSA to assign prescalar to timer0.  Then select the suitable prescaler bit.

I like to do the timer calculation in hertz, for 10ms, it is 100Hz.
So the calculation is
100 = (Fosc/4)/(PSx rate)/timer_value;

my clock frequency is 48Mhz, PSx rate I choose 64 as it can be divided nicely with 48Mhz.

100 = (12,000,000)/64/timer_value;
100 = 18750/timer_value;
timer_value=1875;

So in this case, 16 bits timer is needed, to load the suitable value,
we need take 0xFFFF - 1875, which is 63755.
Another point worth notice is "Any write to the TMR0 register will cause a 2 instruction cycle (2TCY) inhibit", so 63755 needs add with 2. The correct reload value is 63757.

The setting of timer0 module is as follow:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Reset Timer0 to 0x0000
TMR0H = 0;              
TMR0L = 0;

// Clear Timer0 overflow flag
INTCONbits.TMR0IF = 0;  
INTCONbits.TMR0IE = 0;

//Set up timer0 see abive
T0CONbits.TMR0ON=0;         // do not on timer0 first
T0CONbits.T08BIT=0;            // select 16 bits timer
T0CONbits.T0CS=0;               // timer0
T0CONbits.PSA=0;                 // on prescalar
T0CONbits.T0PS=5;               // divide by 64

INTCON2bits.TMR0IP=1;      // enable priority interrupt
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Refer to c18 compiler header file for timer,
(located at "C:\Program Files (x86)\Microchip\mplabc18\v3.47\src\pmc_common\Timers")
I rewrote the timer file and includes following function.

void Timer0_Init(void);
void Timer0_Start(void);
void Timer0_Stop(void);
void Timer0_Write(unsigned int timer0);

When doing initialisation for timer0 at main file,
    //------------------------------------------------------------------------------
    //  Init PIC periphery
    //------------------------------------------------------------------------------
RCONbits.IPEN=1;                  // enable priority interrupt
Timer0_Init();                           // initialise timer0
Timer0_Write(63661);             // load the value to timer0
Timer0_Start();                        // start the timer0
INTCONbits.GIEH=1;            // enable high priority interrupt


Before the interrupt service routine, following interrupt vector table need to be initialised,
//----------------------------------------------------------------------------
// High priority interrupt vector
void InterruptHandlerHigh() ;
#pragma code InterruptVectorHigh = 0x08       // 0x08 for high interrupt vector
void InterruptVectorHigh(void) {
  _asm
    goto InterruptHandlerHigh                             //jump to interrupt routine
  _endasm
}

Interrupt service routine:
//----------------------------------------------------------------------------
// High priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerHigh
//
// Timer0 overflow
void InterruptHandlerHigh() 
{
    if (INTCONbits.TMR0IF) {
INTCONbits.TMR0IF = 0;                 //clear interrupt flag

//set timer int on overflow
    Timer0_Write(63661);                      //write the timer0 value

counter++;
if(counter>=100)                              //count until 1second
{
counter=0;
flag_1sec=1;

}

if(flag_1sec==1)                             //led1 toggle every 1 second
{
flag_1sec=0;
flag_2sec++;
flag_led1=1;
}

if(flag_2sec==2)                           //led2 toggle every 2 second
{
flag_2sec=0;
flag_led2=1;
}
}
}

At the interrupt service routine, I do a counter until 100 to get 1 sec timing, then I raise a flag for led1 at every 1 second; at 2 seconds interval, I raise another flag for led2.

After that, I service the flag for led1, led2 at main routine. (Just a simple blinking)

The overall source code is shown at github.


Friday, October 2, 2015

USB-CDC and HD44780 and DS18B20

Previously, I was learning about the USB-CDC communication and testing the Microchip Libraries for Application. I never really applying the code for my own use. So I was thinking to write something that transfer a string from PC to MCU and display it on HD44780; In addition, I was hoping to transfer string of data from MCU to PC. The idea is getting temperature from DS18B20, convert it to string, and send it to PC whenever I press a push button. While, from the PC side, I am intended to display the message that I have entered in PC terminal software.

To get started, I need to learn about one wire communication, and it turns out to be quit easy. The maxim website has detail descriptions and source code on implementation. There are quit a lot of documents, but the fundamental guide is this one.
It teaches the fundamental of one wire operations like:
write '1' bit
write '0' bit
read bit
and reset
*picture is taken from Maxim website.

After you get the basic idea, application note AN1199 from microchip can really helpful (because I am using the PIC18f). Best of all, it come with source code which compatible with C18, plus detail description of each function is included in AN1199.

Since the purpose is learning, I rewrite the whole source code to suit my own need by referring to microchip's code and some other tutorials I found on-line.

Continuing that, I need to learn the DS18B20 operation, there is one that suit my taste is from nicholas sirirak. Very detail guide and implementation, the best I found so far. Second best, the official datasheet. I read the nicholas sirirak tutorial, and refer back datasheet for part that I don't understand. So far, this approach work very good for me.

The simplest way of getting temperature data is single bus single sensor connection.
The steps are as follow:
1. Reset DS18B20
2. Write SKIP ROM command
3. Write CONVERT T command
4. Wait 750 millisecond or use polling
5. Reset DS18B20 again
6. Write SKIP ROM command
7. Write READ SCRATCHPAD command
8. Read  temperature

The implementation steps are found in the datasheet as follow:

The config can be simply ignored since we are not going to use it.

The DS18B20 actually sending the unsigned int temperature data in two bytes. So in the end, both bytes are combined to form one complete temperature data. The implementation code is as follow:

After that, we need to process the data into something readable.
By referring to table below,

we can see that last 4 bits are for decimal point, and bit 5 to bit 12 are for integer.

In order to process every data in integer format, I create a array that store the decimal point in integer format. Eliminating the floating point computation and save the ram memory.


4 bits maximum value equal to 16, and you take 1 divided by 16, you get the precision until 0.0625. When you pass the last 4 bits of temperature data, the decimal point is directly passed back. Save the computation effort by processing all data in integer.

Later, when I check the microchip cdc function file as shown below,

it seem that it is easier for me to convert the integer to array before passing to "putUSBUSART" function.

it is easy to process the positive temperature. However, for negative temperature, I need to one complement it, then add "one" like following:

temperature =~temperature ;
temperature =temperature +1;

then, the negative number is converted to positive number. 

Let take one example:
actual value                           |                   +10.125                 |                      -10.125
representation in binary        |        0000 0000 1010 0010      |           1111 1111 0101 1110
bitwise "NOT"                      |                         -                       |           0000 0000 1010 0001
add "1"                                  |                        -                        |         0000 0000 1010 0010

I think this process should be called "2nd complement" if I not mistaken.


After I was able to convert all numbers to array, I need to test it, just have the urge to test it.
For high temperature testing, I go and boil the water.


Well, the temperature is lower than I have expected. And it cool down so fast.

For less than zero temperature, I put some salt in water and put it in freezer until it almost frozen.
Finally, I get the negative temperature. My negative temperature conversion to positive temperature is proven to be correct.

To ensure the accuracy of the ds18b20, I need to compare the reading with a real temperature meter. This is where my multimeter come in - vc890c.

My most satisfied equipment so far, acceptable quality and functions with such low price. Come with a thermostat which has wide sensing range from -20 Celsius to 1000 Celsius.

It is a two ways comparison, if the reading is near, then I assume both devices are working good. Actually, it increase the level of confidence of me in China branded multimeter.

I compare the sensing in room temperature and in cold water, the reading is the same, vc890c precision is single digit, while the ds18b20 precision until 4 decimal points.


I have decent multimeter and working code of ds18b20.

Now it the transferring the data to PC. I am using my microchip MLA project file and start editing from that main file.

First include all the library files,

Go to the function - void UserInit(void) and include the lcd initialisation.


Later on, go to ProcessIO(void) and start editing from there.
I want to transmit temperature data each time I pressed a button.
So at the "if(buttonPressed)",
add this instruction "DS18B20_RawTempToBCD(DS18B20_Buffer, &length);".

I want each time I send a temperature data, it will start at new line. From ASCII code, new line code would be 0x0A, so I add 0x0A at end array by using this code "DS18B20_Buffer[length]=0x0A;".
After that, time to send the array using "putUSBUSART(DS18B20_Buffer,length+1);".
I add the 0x0A at the end of array, so I have to increase the DS18B20_Buffer by 1, so I add the length+1 at the putUSBUSART function.

Now, we need to take care of the data sent from PC to micrcontroller,
still in the ProcessIO(void) function,
Go to "if(USBUSARTIsTxTrfReady())", if the numBytesRead contains data, clear the lcd16x2 display,
then display the data at numBytesRead using this instruction "HD44780_WriteData(USB_Out_Buffer[i]);"

That all, from the microcontroller side.

For the PC side, I am using the Termite- Termite is an easy to use and easy to configure RS232 terminal, with an interface similar to that of "messenger" or "chat" programs.

The temperature data obtained is as follow,

At the Termite side, I type the string "hello world" and it is displayed in microcontroller side.

All the codes are shared in github.









Saturday, September 5, 2015

Taobao - abundance supply of cheap tools and components

China has been a great supplier for cheap electronic tools and modules. Even the sparkfun is sourcing their multimeter, soldering station from China, which in turn, show the reliability and usability of China tools.

When you go jalan pasar, most of the components and tools, which I believe also sourced from China.

Recently, taobao has that 2rmb promotion for delivery (direct from china to malaysia) for first time user.

Best of all, you are able to pay taobao using the malaysia online banking system.

A full tutorial is provided by taobao.

Taking this opportunity, I have registered an account and start finding for cheap multimeter and soldering station.

It is lucky that I know Chinese, make it easy for me to search for particular items.
But I also use baidu to help me do the translation and i copy the exact phase to taobao. Although you can use english to search but the results is not as many as your Chinese search term.


The search results return a series of options,


 and depending on cost, I choose the best selling one.

The victor vc890c+, has always been a popular choice. Good review, maybe due to it's fluke like look.


There are a few packages to choose, some with extra chargeable battery, a pouch, probe...
I buy an extra probe. And it only cost me roughly RM60. I think is fairly a good bargain for a multimeter with ac voltage/current (sensing range is until 20 ampere), capacitance, temperature, resistance sensing. Furthermore, transistor NPN/PNP checking is included. A quick search on vc890c+ in lelong, it cost around RM100. So, final conclusion, is a damn good deal.


I have a urge to build my own electronic home lab. So a basic two tools, I think it will be multimeter and solder station. For the soldering station, there are two variants, soldering iron, hot air, and combination or two. At first, I plan to buy soldering iron with hot air reflow, as the price is cheap as well. After saw the technician in my company, on how they can solder smt component easily using single solder iron. I have decided to purchase a soldering station with temperature control.


and I choose the cheapest best selling 936 series.
The Hakko has a tremendous success on soldering station 936, now every China soldering brands will have at least one model with 936 name.

The one I chose is kasadi 936, the name is nice and the advertisement look very promising on assuring the quality. Furthermore, at the taobao page, the reviews on Kasadi 936 are quit ok and has some small defects but still acceptable.

I buy a package which consists solder, solder flux, sucker, tweezer........
Easier for me, as I dont want to buy the items separately as it will troublesome and no guarantee it will be cheaper.

Also, I add in solder cleaner (Reason: Cheap). This type of cleaner is suitable for lazy me, dont need pour water, use and toss item but it can last for quit some times.


In this order, my friend "tumpang" a pair of wifi esp8266 module and a pair of bluetooth ble 4.0 module.




Total delivery fee for these items is roughly 9rmb, 7rmb is charged to deliver the wireless module to a warehouse in china. After consolidating all items, 2rmb is charged for delivery to malaysia. The multimeter and solder station seller doesn't charge fee for delivery in china.


You can check the status of your items from time to time. Even bar code is provided for easy checking, but I never try it.



Taobao will hold your payment for roughly 10 days (I think). You can extend the payment date if the items is not reached within 10 days. Also you can ask for refund but terms and conditions applied (I have no idea on this but it is refundable with conditions).

Nonetheless, my items arrived less than one week (6 days to be exact).



The multimeter set

Solder station


I didnt open my friend wireless module, it is quit light, almost felt empty. I let him open himself.

Total cost for multimeter and soldering station, cost me RM130, but is a good buy. In the mean time, I am going to let it collecting dust in cupboard.