środa, 24 października 2012

Camshaft position wheel simulator

This time a post strictly related to the topic of EFI's. 
Here is a thing I did some time ago. It is a portable simulator of a revolting camshaft. Time to show it:

First, wheels were cut from a 2mm thick steel sheet with a water-jet according to a CAD drawing. It is a decent method of cutting, quite precise. The cut surface is a bit rugged and you can clearly see that the edge is not exactly the right angle, but anyway this method was way better here than plasma or laser cut. You can see some rusty marks caused by the fluid used during cutting.

I cleaned the wheels and painted them later on:

Assembling the wheels on the motor shaft was quite a challenging part. I decided to cut a thread on the shaft and lock the wheel on the shaft with two nuts. I used a hand thread die cause I had no access to a lathe:

The job was very tough, the material of the shaft is very hard and I did not manage to cut the thread perfectly even. The result was good enough though:

The sensor that senses wheel movement is an induction anti-lock braking system sensor, taken from a Polish car called "Polonez" ;) The assembled device looks like this:

And here is the oscillogram of the working device. You can see peaks are not even. That is because the axis of the thread does not cover the axis of the shaft close enough. That causes deviations of the spinning movement. This should not be the problem since the thing that interests us the most are the points where signal crosses through zero. The gap between peaks is a missing tooth that marks the position of the wheel.

czwartek, 31 maja 2012

ARM (STM32) - Blink Led and Interrupt Service Routine in ASM

UPDATE: No need to use GCC linker.

Most beginners tutorials in MCU's do not show how to set up and handle interrupts, and most of tutorials do not show how to code in ASM. Here is a complete tutorial showing how to blink a LED with STM32, set up IRQ and do that in ASM. Assembler is really simple and logic, just bare in mind that almost whatever you write in ASM will be translated straight to machine code. That's the whole secret.

First of all: I love FASM. It's very clear, simple and powerful. Programming huge, modern chips that run without any OS in ASM could be exhausting (there are almost no libraries and macro-instructions that could help out writing bare-metal code - maybe it should be created?) but it allows to understand how the chip works. Let's give it a try:

OS: Windows 7
Compiler: FASMARM download from here
Linker: LD from CodeSourcery none EABI GCC
Processor: STM32f103RB
Development board configuration: GPIOA P0 - button which couples to + VCC, P2 LED - hi state activates it.

 format elf                     ; Output format.  
 processor    37DA2FEh          ; Instruction encoding that fits our processor.  
 thumb                          ; This processor supports only thumb instruction set.  
 include 'vector_macro.inc'     ; Include file with some helpful macros dealing  
                                ; with vector table.  
 section ".text"  
 org 08000000h                  ; Offset address. Both this and placing code in  
                                ; section with an offset is necessary.  
 ; Begining of what goes into flash memory:  
         dw   Stack_Pointer            ; Stack pointer  
         vector _Start                 ; Reset vector  
         vector _NMI_handler           ; Some essential vectors  
         vector _HardFault_handler     ;  
         vector _MemManage_handler     ;  
         vector _BusFault_handler      ;  
         vector _UsageFault_handler    ;  
         default_handler 15            ; Skip 15 unused vectors  
         vector _EXTI_Line0            ; Our handler's address  

         movlit r6, RCC_APB2ENR  
         movs r0, 4h                   ; GPIOA clock enable.  
         str r0, [r6]  

         movlit r6, GPIOA_CRL  
         movlit r0, 0x44444144         ; GPIOA config: P0 floating input  
         str r0, [r6]                  ; P2 - 10MHz output.

         movlit r6, EXTI               ; EXTI line 0 not masked.  
         movlit r0, 0x00000001  
         str r0, [r6]  

         movlit r6, (EXTI + 8)         ; EXTI0 rising trigger selected.  
         movlit r0, 0x00000001  
         str r0, [r6]  

         movlit r6, NVIC               ; Interrupt set enable.  
         movlit r0, 0x40  
         str r0, [r6]  

 ; Values stored in the GPIO output register:  
         movs r2, 0                    ; Turn off LED  
         movs r3, 4h                   ; Turn on LED  
         movlit r6, GPIOA_ODR          ; Point to PortA output data register.  

 loop:                                 ; Infinite loop. Turning the LED on and off.  
         str r2, [r6]                  ; Clear Port A, pin 2, turning on LED.  
         movlit r1, LEDDELAY  
         subs r1, 1  
         bne delay1  
         str r3, [r6]                  ; Set Port A, pin 2, turning off LED.  
         movlit r1, LEDDELAY  
         subs r1, 1  
         bne delay2  
         b loop  

 _EXTI_Line0:                          ; EXTI0 IRQ handler.  
         push {r6}                     ; Let's save whatever we modify on the stack.  
         push {r3}  
         push {r0}

         movlit r6, (EXTI + 0x14)      ; Clear pending IRQ. Otherwise the IRQ would be  
         movlit r0, 1                  ; permanently serviced.  
         str r0, [r6]  

         movlit r6, GPIOA_ODR          ; Point to PortA output data register.  
         str r3, [r6]                  ; Set Port A, pin 2, turning on LED.  

         add r9, 1                     ; When the exception takes place, r9 is being  
                                       ; incremented.  
         pop {r0}
         pop {r3}  
         pop {r6}  

         bx lr                         ; Branch to the address stored in link register.  

            add r0, 1                  ; In case of fault r0 is being incremented  
            b _dummy   
 ; Peripherals addresses:  
     GPIOA_CRL       =  0x40010800  
     GPIOA_ODR       =  0x4001080C  
     RCC_APB2ENR     =  0x40021018  
     EXTI            =  0x40010400  
     AFIO            =  0x40010000  
     NVIC            =  0xE000E100  

 ; Some config:  
     Stack_Pointer   =  0x20005000  
     LEDDELAY        = 1000000    

This is our code. First of all we put a couple of directives informing assembler how the code should be processed. We include a file with macro-definitions (it will be discussed later on). The very first thing that needs to be in the memory is the stack pointer. The second thing is the entry address where execution starts. First thing we do during the actual code execution is peripherals configuration. loop is an infinite loop that turns the led on and off. _EXTI_Line0 is a label defining our ISR.

Save the source in a file called example.ASM

File with some macro-definitions:
 macro vector name {dw name + 1}  
 macro default_handler repeat  
     rept repeat  
         dw _Default_handler + 1  
 macro movlit reg,const {   
     local  .const,.skip   
     ldr   reg,[.const]   
     b    .skip   
     align  4   
     dw   const   

Macro vector creates a label. Adding one to the address is essential cause in Thumb state every address loaded into memory must have LSB set. Macro default_handler creates a certain number of labels referring to a label named _Default_handler. It's necessary to skip unused vectors. Macro movlit is a way to load a const value into a register. Save the macro-definition file in the same place where the source file is and name it vector_macro.inc

Time for the linker script:
     . = 0x08000000; /* start of flash */  
     .text : { *(.text)  }  
     .data :  
     . = 0x20000000;  /*start of internal RAM */ 
     .ram : { *(.ram) }  
     .bss :  

Save the linker script in link.ld

Compile the ASM source file. Your output is an object file called example.O Now we need to link the object file to create an executable file that could be loaded into flash memory. Use command:
$ arm-none-eabi-ld -v -T link.ld -o example.elf example.o 

Once we get the output file we can burn it. I'm using OpenOCD 0.5.0 and JTAG-lock-pick which is fully compatible with Amontec JTAGkey. Run OpenOCD with:
$ openocd -f /interface/jtagkey.cfg -f /target/stm32f1x.cfg

In a new console window connect with openocd server on port 4444:
telnet localhost 4444

Stop the core with:
reset halt

Move the example.elf file to your home folder and burn it in the flash memory:
flash write_image erase example.elf

After a successful download to chip you can start debugging the program. Button pressing causes External IRQ being serviced. To prove it reset the core:

stop it:

check the current register state:

resume the core:

Trigger the interrupt by pressing the button and stop the core one more time:

Check the register state:

you can see that R9 has been incremented during our ISR.

Use step command during halted to watch a single instruction being executed and use mdw address_number to read a word from a certain address. Have fun!

To load the image without linking you need to change the line

 format elf


 format binary as 'bin'

in the source file. Compile it with FASMARM. Fire up OpenOCD and load the image with:

flash write_image erase name_of_the_file.bin 0x8000000

The number in the command indicates the address where the flash memory begins - change it for different chips.

środa, 23 maja 2012

IR reflective tachometer

I had an urgent need to build a simple tachometer. I decided to build one I have already made (although it's avr based) and share the result with you. The project is based on the one that could be found here: http://www.forbot.pl/...24.htm This link contains schematic and both source code and compiled binary file. I just added a 7660s negative voltage converter for LCD polarization.

The IR diode flashes to the rotating element. Once the passing field is black, the IR beam is not being reflected. When it's white, IR reflects, goes back to the phototransistor and activates its current flow. The processor detects the event of white field passing and counts the events, divides by time and displays the result in revolutions per minute.

Phototransistor and an IR diode in one housing. Heat-shrink minimizes IR beam leaks:

IR can't be seen normally, but it's cool how the camera-eye allows us to watch it. Check out your remote controller.

How it works:

If you would like to build one, be aware that you should pull-up reset pin to VCC. Otherwise uC could be unstable.

poniedziałek, 21 maja 2012

Great success!

The Shell Eco Marathon race is over. And the result is very satisfying. Our team with an extremely tight budget passed technical inspection, finished the race (many teams were disqualified because their vehicles exceeded fuel limit for the race or just broke down). Our achievement was the 3rd place in general classification of Urban Diesel category. It's the best place any Polish team ever gained in any category. Plans for the next race: get more $$ from sponsors and upgrade the vehicle. Having more money, we could make marvels.

poniedziałek, 16 kwietnia 2012

What takes my time (Update 15.05.2012)

I've been still for a couple of months due to a whole bunch of work at the University. Right now, I'm involved in a couple of projects, including my engineering degree project (controller for a exhaust wide-band oxygen sensor) and a project of a vehicle for the Shell's Eco Marathon. Our team is constructing the vehicle called "Cetan". It is supposed to compete in SEM's "Urban" category. It will be powered by a 211ccm diesel engine. Here you go for a movie:

The construction is made mostly of fiberglass and aluminium. The total weight of the vehicle must not exceed 205kg. Check out the photos:



Keep your fingers crossed for our project :)

Last night we nearly finished the project and our team with no rest head out to Rotterdam. We had to struggle with a tight budget, therefore we might have problems passing inspection - (Urban category vehicle must have nearly every functionality a regular car does).

czwartek, 17 listopada 2011

ARM GCC Toolchain for Linux - Part 2.

Part 1.

We'll use Eclipse. You can download it from www.eclipse.org. Be sure you choose the "Eclipse IDE for C/C++ Developers". Current release is Indigo. Eclipse does not require installation just un-tar it to the desired destination. Run Eclipse, enter path to the workspace, be careful it must not contain any whitespaces due to compiler problems. Mark that it's the default destination and confirm. On the next screen choose Workbench. Create a new project: File->New->C Project name it, choose the type: (Makefile project > Empty Project > -- Other Toolchain --) and click Finish. Before doing anything go to Project and unmark: Build Automatically and in Project->Clean unmark: Start a built immediately.

Let's tell Eclipse the path to Codesourcery's. Project->Properties->C/C++ Build->Settings chose GNU Elf Parser and input paths to specified files, e.g.:

There is a problem in Eclipse Indigo with system environment variables. We need to specify a path on our own. Project->Properties->C/C++ Build->Environment->Add name it "PATH". As the value put semicolon spaced paths to binutils and CS's compiler. Mine value looks like this:


Eclipse + OpenOCD + GDB.
To get it work we need two plugins. You can install add-ons with Help->Install new software.

The first one is "Eclipse C/C++ GDB Hardware Debugging". Go to Help->Install New Software. Input download directory to the proper dialog:
CDT Optional Features -> C/C++ GDB Hardware Debugging click Install.

The second one is Zylin. Download directory: http://opensource.zylin.com/zylincdt
select "Zylin Embedded CDT" click install. A couple months ago Zylin repository was abandoned but now everything seems to work well.

Running OpenOCD with Eclipse.
You can run external tools with Eclipse with one click of a button.
Run -> External Tools -> External Tools Configurations -> New
Name it depending of your config. IE: "JTAG-Pick-Lock + OpenOCD 0.5 + STM32"
Enter the path to OpenOCD. Mine is:
-f interface/jtagkey.cfg -f target/stm32f1x.cfg
When finish click "Run".

The final step is creating a debugging profile, so you can enter debugging mode just with a click of the bug button. Go to:
Run -> Debug Configuration

Create a new configuration by double-clicking "GDB Hardware Debugging".Configuration is bounded to the project. You need to specify path to your project and specify executable that will be debugged. Last thing to do in this tab is changing GDB (DFS) Hardware Debugging Launcher. Click select other, mark "Use configuration specific setting" and choose "Standard GDB Hardware Debugging Launcher"

Go to tab named Debugger and specify path to CS's GDB. Mine path:

Find a dialog box called "Port number" and enter value 3333

Go to tab Startup, unmark "Reset and Delay", unmark "Halt". Enter initialization commands to the dialog:
monitor reset halt

Mark "Set breakpoint at:" and enter
to the associated dialog.

Mark "Resume".

This is it. To start your debugging session click "Debug".
Have fun!

środa, 16 listopada 2011

ARM GCC Toolchain for Linux - Part 1.

This post is inspired by Freddie Chopin's tutorial showing how to install and configure a free IDE for programming/debugging ARM chips with no output limit. It's available on www.freddiechopin.info Since it's for Windows, a bit outdated and in Polish I decided to brief it here.

IMPORTANT UPDATE (17.02.2013): After completing reading the tutorial, before downloading any software please go to page http://www.freddiechopin.info/en/articles/35-arm/87-bleeding-edge-toolchain-o-co-chodzi and consider using Freddie's toolchain instead the one from CodeSourcery (Mentor).

System: Debian Squeeze 2.6.32-5-686.
JTAG-Pick-Lock (Amontec JTAG-Key)
Target: STM32

We'll be using Eclipse as IDE, Sourcery G++ Lite as toolchain, OpenOCD as debugger.

Download from http://www.mentor.com/ Search for "Sourcery G++ Lite for ARM EABI". Since it's a bit tricky to find it, here is a direct link for current release: https://sourcery.mentor.com/sgpp/lite/arm/portal/release1802

Install with:
$ sudo sh

The installer will ask if you want to modify PATH. Confirm this. After installation check if it succeed. Create file main.c with simple code:

int main(void)
return 0;

Try to compile it with:
$ arm-none-eabi-gcc main.c

If you get something like:
/opt/sourcery/bin/../lib/gcc/arm-none-eabi/4.5.2/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 00008018

and compiler outputs file a.out everything should be ok.

IF your system PATH still isn't updated you need to edit /etc/profile. Add
export PATH=$PATH:/your/path/to/sourcery/bin
to the file. Go back to previous step to check if everything works.

Current version of OpenOCD is 0.5.0. Download it form http://openocd.sourceforge.net/

Jtag-Pick-Lock (Amontec Jtag-Key) is FT2232 based. Basically you have to install libftdi-dev and compile OpenOCD with:
$ sudo ./configure --enable-ft2232_libftdi --enable-usbprog
$ make
$ make install

Smooth and easy. Check if it installed correctly:
$ openocd --version

Check if it works:
$ sudo openocd -f interface/jtagkey.cfg -f target/stm32f1x.cfg

OpenOCD should respond like this:

Open On-Chip Debugger 0.5.0 (2011-11-15-22:39)
Licensed under GNU GPL v2
For bug reports, read
Info : only one transport option; autoselect 'jtag'
1000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
cortex_m3 reset_config sysresetreq
Info : clock speed 1000 kHz
Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
Info : JTAG tap: stm32.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
Info : stm32.cpu: hardware has 6 breakpoints, 4 watchpoints

If it does work, you need to add a rule that will allow regular users to use the dongle. Create a file:
that contains:
SYSFS{idVendor}=="0403", MODE="666", GROUP="users"
(vendor depends on JTAG you use). Save and add your user to the chosen group.

Now you can debug from regular user's account, yay!