Wednesday, 31 May 2017

Programming the Arduino Uno without using Arduino IDE

https://github.com/RealTimeEngineers/Arduino_programming_without_Arduino_IDE


It is possible to program the Arduino Uno without the use of Arduino IDE.

Download the WinAVR tools from the below link

https://sourceforge.net/projects/winavr/files/latest/download

After installation you can find the AVR tools in C:\WinAVR-20100110\bin



Open Notepad and save the below code as blinky.c and place it in some folder say 'test_blinky'


/*
 * Blinks LED on connected to pin 13 (PB5 on Atmega328P)
 *
 * Authors : Jabez Winston C, Hariharan K
 *
 */

#define F_CPU 16e6  // Arduino Uno's ATmega328P runs at 16MHz 

#include<avr/io.h>
#include<util/delay.h>

int main()
{
DDRB|=(1<<5); //Set PB5 as output by setting 5th bit DDRB register  

 while(1)
 {
 PORTB|=(1<<5);  //Set pin 13 (PB5)- High
 _delay_ms(100); //Wait for 100 ms
 PORTB&=~(1<<5); //Set pin 13 (PB5)- Low
 _delay_ms(100); //Wait for 100ms
 }
return 0; 
//Refer Atmega328P datasheet for details regarding DDRB and PORTB
}


Inside the folder 'test_blinky' ,with SHIFT key pressed ,right click and select Open command window here


Type the following commands on command prompt

avr-gcc -O2 -mmcu=atmega328p blinky.c 
avr-objcopy -O ihex a.out a.hex

The first command compiles the program with optimization level 2 (O2) and


To flash the HEX file (a.hex) to Arduino ,use the below command
avrdude -patmega328p -carduino -PCOM25 -b115200 -D -Uflash:w:a.hex:i

Replace COM25 port by the COM port for your Arduino by looking into the device manager
-Uflash:w:a.hex:i tells the avrdude utility to (w)rite (i)ntel hex file (a.hex) to flash memory.
-b115200 tells at what baud rate avrdude should communicate with the bootloader. Here it is 115200.Changing it to some other value won't work.


To automate the 3 steps, a batch file is written which does the process of compiling,HEX file conversion and flashing the HEX file.Save the below code as build_and_flash.bat in test_blinky folder and run it.

del *.hex *.out

avr-gcc -O2 -mmcu=atmega328p blinky.c 
avr-objcopy -O ihex a.out a.hex
avrdude -patmega328p -carduino -PCOM25 -b115200 -D -Uflash:w:a.hex:i

pause


Complete work is found in this github link
https://github.com/RealTimeEngineers/Arduino_programming_without_Arduino_IDE

How was it found that it works this way ?

Go to File -> Preferences in Arduino IDE



































Enable verbose output during compilation and upload


Arduino IDE showing the commands executed in background during compilation and upload



Arduino's AVR tools can be found in C:\Program Files (x86)\Arduino\hardware\tools\avr\bin . Those tools can also be used instead of WinAVR tools.


The below batch file makes use Arduino AVR tools. Save as build_and_flash_arduino_tools.bat and make  use of it.

@echo off

::Add 'C:\Program Files (x86)\Arduino\hardware\tools\avr\bin' to environment variable PATH
set PATH=C:\Program Files (x86)\Arduino\hardware\tools\avr\bin;%PATH%
 
:: Delete all .hex and .out files 
del *.hex *.out

:: Compile 'blinky.c' for ATmega328p chip using 'avr-gcc' to generate 'a.out' 
avr-gcc -O2 -mmcu=atmega328p blinky.c 

:: Convert 'a.out' to Intel HEX file 'a.hex' using 'avr-objcopy'
avr-objcopy -O ihex a.out a.hex

:: Burn the HEX file(a.hex) to ATmega328 chip on Arduino Uno using 'avrdude'
:: Replace COM25 by the COM port detected on your PC
avrdude -C"C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"  -patmega328p -carduino -PCOM25 -b115200 -D -Uflash:w:a.hex:i

::Don't close console after execution
pause

Friday, 31 March 2017

Controller Area Netrwork (CAN) in Linux

1. Install CAN-Utils

Method 1:

Using the command
sudo apt-get install can-utils




(OR)



After downloading use the following commands

unzip can-utils-master.zip
cd can-utils-master
make
sudo make install

2.Load CAN drivers (Reference: https://en.wikipedia.org/wiki/SocketCAN )

Use the following commands

sudo modprobe can
sudo modprobe vcan
sudo modprobe can_raw
sudo modprobe can_gw

To list the kernel modules
lsmod



Kernel modules can be found in /lib/modules/<kernel_version>/net/can/
(or) <KERNEL_SRC>/net/can . Kernel source can be downloaded from www.kernel.org


3.Creating virtual CAN node( Reference: https://en.wikipedia.org/wiki/SocketCAN )
Use the following commands to create a virtual CAN node vcan0

sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

Similarly repeat the above commands to a virtual CAN node vcan1



To list the details of network interfaces ,use ifconfig
Use ifconfig vcan0 to know details of vcan0




4.Using CAN-Utils

CAN Utils contains the following tools
asc2log, bcmserver, canbusload, can-calc-bit-timing, candump, canfdtest, cangen, cangw, canlogserver, canplayer, cansend, cansniffer, isotpdump, isotprecv, isotpperf, isotpsend, isotpserver, isotpsniffer, isotptun, log2asc, log2long, slcan_attach, slcand and slcanpty

Frequently used tools are highlighted

 a.cansend and candump

To send a CAN message , using cansend there are two requirements 11 bit(0x000 to 0x7FF) /29 bit(0x00000000 to 0x1FFFFFFF) identifier and message of length ranging from 0 to 8 bytes

To send a message (0x6789) of 2 bytes with 11bit identifier (0x000) to interface vcan0,use cansend vcan0 000#6789

To send a message (0x8679) of 8 bytes with 29 bit identifier (0x0123456789ABCDEF) to interface vcan0,use cansend vcan0 0x0123456789ABCDEF#8679



Using Acceptance filtering (Refer https://discuss.cantact.io/t/using-can-utils/24 )

To filter messages whose ID is in the range  0x120 to 0x12F
Use candump vcan0,120:0x7F0
Messages are filtered based on this condition
[received_can_id] & [can_mask] == [can_id] & [can_mask]
Here can_id = 0x120 and can_mask =0x7F0
& is a bitwise operator



b.Using the CAN gateway utility (cangw):

Ensure that kernel module can_gw  is loaded.You can check it using the command lsmod

sudo cangw -F                                                            
 #deletes all gateway rules

sudo cangw -A -s vcan0 -d vcan1 -e -f 120:7F0      
 #Adds a new rule with source as vcan0 , destination as vcan1 with echo enabled and  which accepts messages of ID in the range     0x120 to 0x12F

sudo cangw -A -s vcan0 -d vcan1 -e -f 200:7F0       
#Adds a new rule with source as vcan0 destination as vcan1 with echo enabled and   which accepts messages of ID in the range  0x200 to 0x20F

cangw -L           
#Lists all gateway rules



d. using cangen
For more help and information, <utility_name> --help

Eg:       cangw --help
      cansend --help
      candump --help




Linux CAN Subsystem

For working on real CAN hardware
https://harrisonsand.com/can-on-the-raspberry-pi/


Friday, 25 December 2015

C to Assembly conversion using ARM DS-5

Converting a C program to Assembly Program using ARM DS-5.

The best way to learn ARM assembly is by converting a C language program to Assembly.

1.First we'll set the Environment Variable. Press Winkey+R to open Run. Type SystemPropertiesAdvanced and press Enter


Click Environment Variables .Meanwhile open DS-5 vx.xx Command Prompt from Start Menu.





2.Click New...  in User variables . Set variable name as Path and Variable Name as dispalyed in DS-5 command prompt.In my case it is C:\Program Files\DS-5 v5.22.0\bin


Click OK when finished.

3.Now close and reopen DS-5 command prompt.
Use select_default_toolchain to change the compiler. Here I chose ARM Compiler 5


4.Now open Notepad and type the following source code.

void main()
{
int a[5],i;

for(i=0;i<5;i++)
       {
       a[i]=0;
       }
      
}


stdio.h is not necessary as printf,scanf aren't used. Save it as somename.c .In my case I named it as Ex1.c.The C file is in D:\C2ASM .Keep the file in a location as you wish.Using the command armcc -S somename.c generates somename.s which contains the assembly code.

Commands

D:
cd C2ASM
armcc -S Ex1.c



Warnings can be ignored. Now open  Ex1.s file. Now the check the highlighted code and ignore the remaining. You come across new instructions such as STR(Store) ,CMP(Compare),BX(Branch with exchange),BLT(Branch if less than) etc.,




        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        SUB      sp,sp,#0x14        ; Allocate 5*4 = 20B = 0x14 for array a
        MOV      r0,#0              ; i=0
        MOV      r1,r0              ; Load 0 in r1
        MOV      r2,sp              ; Starting address of array a is stored in r2
|L0.16|
        STR      r1,[r2,r0,LSL #2] ; 0-->address[r2 + 4*r0] or *a+4*i or a[i]=0 in C
        ADD      r0,r0,#1          ; r0=r0+1 or i=i+1 or i++
        CMP      r0,#5             ; Compare i and 5
        BLT      |L0.16|           ; if i < 5 jump to |L0.16|
        ADD      sp,sp,#0x14       ; De-allocate memory for array a
        BX       lr                ; Return
        ENDP

Note: Size of int is 4 B and hence 4 memory locations are need.To understand the working of BLT ,knowledge of conditional execution of ARM instructions and CPSR , SPSR registers is required.

Alternate way to perform C to assembly conversion:

1.Create a new C project.Add a new C file to the project and add code as shown below


Build project and open the .axf file in Debug folder.Click Disassembly Tab


Scroll through and search for main . The remaining code is related to C Run time and it is one of the reasons why code written in C is larger than in assembly.


A few more programs....

1.Calculating sum of 6 numbers

C code:
void main()
{
       int i,a[6];
       volatile int sum=0;
       for(i=0;i<6;i++)
              sum+=a[i];
      
}

Equivalent Assembly Code:

        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        SUB      sp,sp,#0x1c                    ; allocate space for sum and a[5] ie 24 B = 0x1C
        MOV      r0,#0                          ; i=0
        MOV      r1,sp                          ; pointer for a
        STR      r0,[sp,#0x18]                  ; 0 --> sum
|L1.16|
        LDR      r2,[r1,r0,LSL #2]              ; r2 <-- a[i]
        LDR      r3,[sp,#0x18]                  ; r3 <-- sum
        ADD      r0,r0,#1                       ; i++
        ADD      r2,r2,r3                       ; r2<--a[i]+sum 
        CMP      r0,#6                          ; Compare i and 6
        STR      r2,[sp,#0x18]                  ; r2 -->sum
        BLT      |L1.16|                        ; Is i<6 then jump to L1.16
        ADD      sp,sp,#0x1c                    ; Un allocate space
        BX       lr                             ; return
        ENDP


2.To compute the value of f(x) = x3 + 3x2 + 3x + 1 using function.

C code:
//  To perform f(x) = x^3+3x^2+3x+1

int func(int);

void main()
{
volatile int x,p;
/* volatile keyword prevents the compiler from performing optimizations on variables */
p=func(x);
}

int func(int x)
{
int f;
f=x*x*x +3*x*x +3*x +1;
return f;
}

Equivalent Assembly Code:


        AREA ||.text||, CODE, READONLY, ALIGN=2

func PROC
        ADD      r2,r0,#3         ; r2 = r0 +3            x+3
        MUL      r2,r0,r2         ; r2 = r0 * r2          x*(x+3)
        ADD      r1,r0,r0,LSL #1  ; r1 = r0 + 2*r0        3x
        MLA      r0,r2,r0,r1      ; r0 = r2 * r0 + r1     x*x(x+3)+3x ie x^3+3x^2+3x
        ADD      r0,r0,#1         ; r0 = r0 + r1          x^3 + 3x^2 + 3x + 1
        BX       lr               ; Return to main
        ENDP

main PROC
        PUSH     {r3,lr}          ; Push r3 and lr to stack
        LDR      r0,[sp,#0]       ; r0 <-- x
        BL       func             ; Call func
        STR      r0,[sp,#0]       ; x is no more needed,So save f in same location occupied by x
        POP      {r3,pc}
        ENDP

3.Switch case statement

C code:

void main()
{
volatile int a;
volatile char b;
switch(a)
       {
       case 1: b= 'R';
               break;
             
       case 2: b= 'A';
               break;

       case 3: b= 'M';
               break;
             
       default: b='Y';
             
       }
}
Equivalent Assembly Code:

        AREA ||.text||, CODE, READONLY, ALIGN=2

main PROC
        PUSH     {r3,lr}
       
        LDR      r0,[sp,#0]       ; r0 <-- a
       
        CMP      r0,#1            ; compare r0 and 1
        MOVEQ    r0,#0x52         ; r0 <--'R' if (r0 = 1 ie a = 1)
        BEQ      |L0.44|          ; Jump to |L0.44|
       
        CMP      r0,#2            ; compare r0 and 2
        MOVEQ    r0,#0x41         ; r0 <--'A' if (r0 = 2 ie a = 2)
        BEQ      |L0.44|          ; Jump to |L0.44|
       
        CMP      r0,#3            ; compare r0 and 3
        MOVNE    r0,#0x59         ; default case r0 <-- 'Y'
        MOVEQ    r0,#0x4d         ; r0 <--'M' if (r0 = 3 ie a = 3)
|L0.44|
        STRB     r0,[sp,#0]       ; r0 --> b
        POP      {r3,pc}
        ENDP

ASCII values R-0x52 , A - 0x41 , M -0x4d ,Y-0x49 
You can see from the examples that some variables go out of scope and memory is de-allocated even when the function doesn't go out scope.

In example 2 , variable x loses its scope and gets de-allocated as soon as it is loaded to r0 register.The location is used by f later.
In example 3, variable a loses its scope and gets de-allocated as soon as it is loaded to r0 register. The location is used by b later.

The ARM compiler optimizes the code to a great extent to minimize memory usage.
ARM is based on load-store architecture unlike Intel x86 and hence when any operation needs to be performed ,
                >Operands are loaded into the registers
                >Operations are performed and stored in registers
                >From registers the result is stored in the memory
Big calculations involving numerous operations are performed in this way.ARM compiler effectively uses only 16 registers out of which 3 registers are reserved for Stack pointer,Link register and Program Counter. 


ARM instruction set is covered elaborately in this PPT