Last week I was browsing my old backup hard drive and I found a source code for a very simple PIC based digital timer that I made a couple of years ago. The actual hardware of the project isn’t with me anymore. I might have lost it when I moved from my old apartment into my new home. However, I thought this might be a good practice project for beginners and so I am sharing it here. I am not going to build it from scratch again; I will rather demonstrate it using my DIY PIC16F628A breadboard module and I/O board. The complete circuit diagram along with the firmware developed using mikroC Pro for PIC compiler is provided in the article.

0-99 minute timer

Circuit diagram

As I mentioned earlier, the microcontroller used in this project is PIC16F628A running at 4.0 MHz clock using an external crystal. An HD44780 based 16×2 character LCD is the main display unit of the project where you can watch and set the timer duration using tact switch inputs. There are three tact switches connected to RB0 (Start/Stop), RB1 (Unit), and RB2 (Ten) pins. You can select the timer interval from 0-99 min using Unit and Ten minute switches. The Start/Stop switch is for toggling the timer ON and OFF. When the timer gets ON, a logic high signal appears on the RA3 pin, which can be used to switch on a Relay. The circuit diagram of this project is described below.

0-99 minute timer circuit

I am using my self-made breadboard module for PIC16F628A and experimenter’s I/O board here to demonstrate this project. Since there is no relay switch in the I/O board, I am connecting the timer output (pin RA3) to an LED. When the timer starts, the LED is turned ON. As the timer duration is elapsed, the LED is turned OFF.

Circuit setup

Operation of the Timer 

When the device is powered ON, the microcontroller initializes the LCD display and shows the following message. The timer is initially OFF and so does the LED or relay, whichever is connected to RA3 pin.

Message displayed at power on

You can set time duration between 00-99 min (in step of 1 min) using the Unit and Ten tact switches. Each switch press will increment the corresponding time digit.

Setting timer minute

When the desired time is set, press the Start/Stop switch to turn ON the timer. The RA3 pin goes high (LED glows) and the count down begins. When the timer is ON, the remaining time is also shown on the LCD screen. When the time elapsed, the timer stops and the LED turns OFF. You can interrupt and stop the timer at anytime by pressing the Start/Stop switch once more.

Displaying the left over time on LCD

Software

The firmware for PIC is developed using mikroC Pro for PIC compiler. The use of Timers are avoided for simplicity. The time delays are created using the Delay_ms() function of mikroC, which seems to give reasonably accurate timing delays.

Download mikroC source code and HEX file

For a more advanced digital timer switch, read my another project: Programmable digital timer.

[via: http://embedded-lab.com/]

 

STM32F103ZET6 board comes with 3.2 inch graphical LCD which features an ILI9320 controller. Equipped LCD is capable of displaying 252144 colors when driven in 18-bit mode. We are gonna drive it in 16-bit mode, so we are limiting it to 65K colors.

LCD driver is based on existing code found on internet which was originally developed for STM3210E board. Only minor modifications were needed like assigning right control pins.

STM32F103ZET6 board was designed so that LCD was connected to Flexible Static Memory Controller (FSMC) of STM32. FSCM allows connecting most of external parallel memory types like ROM, SRAM, NOR Flash, NAND Flash. ILI9320 driven LCD is connected in 16-bit mode to FSMC Bank1 4th subpage and is seen as SRAM memory, so once configured controlling LCD becomes same as writing to SRAM. LCD memory starts from address 0x6C000000

#define LCD_BASE ((u32)(0x60000000 | 0x0C000000))#define LCD ((LCD_TypeDef *) LCD_BASE)

LCD is controlled by using index register which points to selected register and with next operation we can write to its memory. So for this there is a simple structure used:

what allows writing to register with simple routine:

voidLCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue){//Write 16-bit Index, then Write RegLCD->LCD_REG = LCD_Reg;LCD->LCD_RAM = LCD_RegValue;}

There are 152 registers used to control LCD and most of these has to be initialized before accessing LCD. As I mentioned it is already done in LCD library no need to wary for now. In attached project you’ll find a working example of LCD which simply displays a bitmap image stored in MCU SRAM.

By pressing one of four buttons you can cycle through other functions like drawing simple shapes, displaying text and drawing sine wave. Hopefully you’ll find this useful. STM32F103ZET6GLCD

[via: http://www.scienceprog.com/]

 

Normally one tact switch requires one digital input pin of a microcontroller. Some designs implement keypad style multiplexing to get multiple switches on fewer inputs. However, there exist other techniques that allow you to connect many switches on a single input pin of a microcontroller. This tutorial demonstrates one such technique as applied to PIC12F683 microcontroller. In this example, there are four LEDs and four tact switches connected to the PIC12F683 microcontroller. While each LED is controlled through an individual I/O pin, the four switches are connected to one ADC input pin of the PIC12F683 microcontroller.

Connecting multiple tact switches to one input pin of PIC micro

Theory

The theory of connecting multiple switches on a single ADC input channel is very simple. One end of each switch is connected to the power supply voltage through an individual pull-up resistor, whereas the other end is grounded through a common resistor. When a switch is pressed, it creates a voltage divider network between the power supply and ground terminals. The value of the divided voltage can be made unique for all four switches by selecting different values of pull-up resistors. The voltage is then measured with the ADC to determine which switch has been pressed.

The circuit diagram shown below will probably give you a more clear picture of this technique. There are four switches (SW1-Sw4) connected to the AN0 input pin of the PIC12F683 microcontroller. Their one end is grounded through a common resistor R (=470 Ω), whereas the other end is pulled high through different value resistors (R1‘-R4‘), giving rise to different values of the voltage divider output. The voltage drop across the resistor R is thus unique for each switch press and is measured through the AN0 ADC channel. When no switch is pressed, the AN0 pin is pulled low through R, and the ADC should ideally measure 0 V.

Circuit diagram for connecting four tact switches to one ADC input channel of PIC12F683

There are four LEDs (LED1-LED4) connected to pins GP1, GP2, GP4, and GP5 of the PIC12F683 microcontroller. They will be toggled ON and OFF through the four switches.

Calculation of resistor R’

The resistors R1‘ – R4‘ determine the value of the voltage divider output for each switch press. We know that each resistor value must be different to create an unique analog voltage output across R for each switch. But how should we select their values? You should keep in mind that the resistors do have certain tolerance values and their values also change with temperature. Therefore, you should provide enough gap between any two consecutive values of the voltage divider output to avoid any conflict. The best practice would be to implement an evenly spaced values of the voltage divider for all 4 switches. Remember that when you press a switch, you should not expect a precise value of the analog voltage across the resistor R. It would fluctuate little bit within a certain range which is defined by the resistors’ tolerance values, temperature, contact resistance of the switches, and the stability of the power supply voltage. So, in order to identify the switch, what you are actually looking at is a range of voltage that the voltage divider output falls in.

The table below shows the ranges of DN defined for all four switches, and the corresponding values for resistor R’. DN stands for digital number and represents the 10-bit A/D conversion output, which is proportional to the input analog voltage. Suppose, we define the DN range of switch SW1 as 100-300. Our goal is to find the appropriate value of R’ to ensure that when SW1 is pressed, the 10-bit A/D output will be always in between 100 and 300 count. The minimum value of R’ would correspond to the maximum value of the count, which is 300 for SW1. The equation to find R’ for DN = 100 is,

1024*R/(R+R’) = 100, where R = 470 Ω.

This gives, R’ = 4342.8 Ω. Similarly, for DN = 300, the value of R’ should be 1134.3 Ω. Therefore, R’= 2.2 K would be an appropriate value for SW1. The rest of the R’ values for other switches are shown in the table below.

Table showing the appropriate values of R’ for voltage divider network

Circuit setup on a breadboard

Software

The software involves few if checks to compare the A/D output with the predefined ranges to determine the switch that has been pressed.

ADC_Value = ADC_Read(0);if(ADC_Value > 700) {// SW4 is pressedLED4 = ~LED4;Delay_250ms();}if(ADC_Value > 500 && ADC_Value < 700) {// SW3 is pressedLED3 = ~LED3;Delay_250ms();}if(ADC_Value > 300 && ADC_Value < 500) {// SW2 is pressedLED2 = ~LED2;Delay_250ms();}if(ADC_Value > 100 && ADC_Value < 300) {// SW1 is pressedLED1 = ~LED1;Delay_250ms();}

Download complete mikroC source code and HEX file

Note: The microcontroller runs at 4.0 MHz using its internal clock source and the MCLR is disabled.

Each tact switch toggles an LED ON and OFF

Summary

A technique of interfacing multiple tact switches using a single ADC input pin was demonstrated using the PIC12F683 microcontroller. A digital input from four tact switches were individually read through the AN0 ADC channel and displayed it back on an LED. While this technique saves input pins and reduces the size, one downside of the design is detecting combination of switches. The calculations of R’ resistors become more complex in such a case. The resistor values must be chosen very carefully so that the voltage resulting from a switch combination is unique.

[via: http://embedded-lab.com/]

 

Couple years ago I have purchased LPC2148 development board called BlueBoard form ngxtexhnologes. It is quite powerful board with ATM7TDMI series microcontroller which is considered an old guy comparing to Cortex ones. But still these are widely used and are powerful.

Development board has some handy features installed. 12MHz crustal allowing to run processor at full 60Mhz speed. Couple RS232 ports, VGA connector, PS/2 connector for keyboard or mouse, 20-pin JTAG, SD/MMC slot, USB B-type, 8 LEDs driven with serial-in parallel-out shift register, 2×16 LCD, buzzer, audio jack with amplifier, two programmable buttons and 256Kb of I2C interfaced EEPROM. Microcontroller itself has 512KB of internal flash and 32+8KB of RAM. All ports are accessible and any external hardware can be disconnected with jumpers. This is great board for prototyping and end application.

I decided to put up a simple project. And yes, you guessed – LEDs again. Blueboard website provides with code examples. Most of drivers are already written this makes our life much easier. Only minor modifications will be needed as their code is based on (or related to TNKernel real-time kernel). For now I just want to get rid of RTOS based code and make simple application.

Our project will be based on same tools as we used for STM32F103ZET6 development board. So no additional preparation is needed – just open Eclipse (CodeSourcery must be installed too). The only thing you will need is different firmware flasher as LPC2148 is NXP product. For this there is great program called Flash magic that uploads compiled code by using build in bootloader.

Project setup is nothing more than collection of files collected from different sources. These include linker scripts, start-up codes, makefile. You can find board drivers on NGX website within example code.

[You can download project package here that strobes all 8 LEDs here:LPC2148LED]

Lets see how these LEDs are controlled. As we mentioned above, LEDs are connected through serial to parallel shift register which is controlled via SPI interface:

For this we are going to need drive SPI peripheral of microcontroller and also drive register itself so we could access individual LEDs. For this we must include spi.h library that was already in example package. Originally there were separate source files for 74HC595N register and led. But this seems unnecessary while register and leds comes along, so I simply merged those libraries in to led.h and made a little cleanup to get rid of few rtos based functions.

After preparation we can write simple application that gives strobe effect on LEDs:

#include "type.h"#include "hardware.h"S32 main(void){HardwareInit();test_leds();while(1){leds_on();delay(10000);turn_off_all_leds();delay(190000);}return 1;}

Here you can a HardwareInit() function from hardware.c, which simply takes care of setting up a PLL multiplier where 12MHz crystal frequency are multiplied to 60MHz that clocks MCU core. SPI peripheral is initialized here too.

Hope you find this information useful.

[via: http://www.scienceprog.com/]

 

Found some time to play with STM32F103ZET6 development board and decided to set up a simple project for it. Probably the trickiest part of this is to set up a project environment that would serve as template for following developments. Obviously we choose GCC development tools. Many ARM developers chose CodeSourcery Lite edition toolchain. It has full command line functionality – this is what we usually need. If you want some alternative – you can choose Yagarto GNU ARM toolchain which is also great and free.

No matter which tool you select code will work on both. Lets stick to CodeSourcery. Just download it and install to your PC. As we said Lite version supports only command line tools – we need an interface for it. Eclipse IDE is one of favorite choices, so we will grab this one too. Yagarto website has a nice tutorial on how to setup Eclipse IDE in step-by-step manner. We wont go in to details with this.

Say we have development environment up and running. There is still one piece needed – flash programming software. ARM Cortex-M3 microcontrollers come with preloaded bootloader that allows uploading firmware via RS232 (or USART to USB converter). For this ST has prepared a special software called Flash Loader Demonstrator. With it you will be able to upload .hex files simply using RS232 cable. Also there are other options like using Jtag adapter.

Now we can proceed to setting up our project base. Compiler itself doesn’t know about microcontroller you are using. This is why we have to define how much memory is available on chip also outside of chip. Then we need to indicate memory sections, stack, heap. Then we need to allocate interrupt table in flash memory and do many other tasks before running actual program. These tasks are descibed in linker script and startup code. There is no need to write startup code and linker scriopts from scratch. There are plenty of working examples in internet. For this example we are going to borrow these from Michael Fisher (STM3210ETest) used in yagarto. Just be sure that Memory parameters are set correctly. In our case lines in files (stm32f103xe_flash.ld and stm32f103xe_ram.ld)should be:

MEMORY{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512KRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K}

Also we are going to use Standard Peripheral Library which will make easier to program MCU peripherals as it has all necessary register definitions and CMSIS driver functions allowing to access peripherals with unified functions. Currently there is v3.5.0 version of library.

Now we have everything we need. Next we open Eclipse IDE and go to workbench where we select menu File->New. Enter desired Project name. Then select Makefile->Empty project. In toolchain list select Other Toolchain. Click Finish button.

In project explorer you should see project folder with selected name. We are going to make some folder structure so each library and device files wouldn’t mix with each other.

Now we can start copying some files in to directories. First of all from STM3210ETest package copy stm32f103xe_flash.ld and stm32f103xe_ram.ld files to linker directory. Then crt.c and vectors_stm32f10x_hd.c copy to startup directory. Next we need to copy CMSIS and STM32F10x_StdPeriph_Driver folders as follows:

According to stm32f10x.h file we also need stm32f10x_conf.h file where we need to include necessary peripheral library headers. You can find this file in STM3210E-EVAL package. Place this file in root directory. Also you can grab stm32f10x_it.h and stm32f10x_it.c files where we will write our future interrupt handlers.

Now we just create main.c in project root directory where we will write our code. And of course you will need a makefile to compile project. You will find it in a project package as it takes quite significant space. As we are going to blink LEDs this time lets create a driver. In Drivers directory add two now source files leds.c and leds.h. Now we have full project template that we can use for most of projects.

First of all take care of LEDs driver. All we need is to initialize pins where LEDs are connected. For this we make function:

void LEDsInit(void){//GPIO structure used to initialize LED portGPIO_InitTypeDef GPIO_InitStructure;//Enable clock on APB2 pripheral bus where LEDs are connectedRCC_APB2PeriphClockCmd(LEDPORTCLK,ENABLE);//select pins to initialize LEDGPIO_InitStructure.GPIO_Pin = LED1|LED2|LED3|LED4|LED5;//select output push-pull modeGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//select GPIO speedGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(LEDPORT, &GPIO_InitStructure);//initially LEDs offGPIO_SetBits(LEDPORT, LED1|LED2|LED3|LED4|LED5);}

As you can see peripherals are initialized through structures. To initialize ports we simply create GPIO_InitTypeDef variable where we define variables and then pass structure as parameter to GPIO_Init function. To configure port we simply select what pins we are going to use. Then we select pin mode (in our case its push-pull output) and then select maximum speed.

But before we do initialization we need to enable port bus clock. As LED port is connected to APB2 bus then we use RCC_APB2PriphClockCmd function where we simply enable this port.

After LEDs are initialized we can turn them on, turn off and toggle with following functions:

voidLEDOn(uint32_t);voidLEDOff(uint32_t);voidLEDToggle(uint32_t);

To control port pins we are using atomic bit manipulation with functions:

GPIO_SetBits(LEDPORT, LED1);GPIO_ResetBits(LEDPORT, LED4);GPIO_ReadOutputDataBit(LEDPORT, LED3);

After LEDs driver is ready we can write simple program that sweeps all 5 leds:

//running LEDs#include "stm32f10x.h"#include "leds.h"//delay functionvoid Delay(__IO uint32_t nCount){for(; nCount != 0; nCount--);}int main(void){//init ledsLEDsInit();while (1){LEDToggle(1);Delay(500000);LEDToggle(2);Delay(500000);LEDToggle(3);Delay(500000);LEDToggle(4);Delay(500000);LEDToggle(5);Delay(500000);}}

All is left to connect board to computer with RS232 cable and upload .hex to microcontroller flash memory.

[Download project template]

[via: http://www.scienceprog.com/]

 

In previous example we implemented a simple demo program that reads buttons by constantly checking their status in main program loop. Obviously this isn’t efficient and convenient way to do that. Imagine your program has to do lots of tasks and in between you also need to check button status – mission becomes impossible unless you use interrupts. In this part we briefly introduce to STM32F10x interrupt system and write example code where LEDs and buttons are serviced within interrupts.

ARM Cortex-M3 microcontrollers have advanced interrupt system that is pretty easy manageable. All interrupts are controlled inside Nested Vectored Interrupt Controller (NVIC) which is close to Cortex core to ensure low latency and robust performance. Main features of NVIC include:

  • Interrupt preemption – automatic support for nested interrupts where higher level exception may interrupt lower level that is currently processed. NVIC takes care of saving context to stack. As everything is done in hardware there is no need for assembler wrappers like we do in other MCUS. All is needed is to ensure that you won’t run out of stack memory and set right interrupt priorities;

  • Tail chaining – it’s a mechanism allowing to reduce latency if exception occurs during or just after current ISR routine. In this case MCU doesn’t have to do full unstacking that allows to enter another pending exception as soon as possible.

  • Late arrivals – feature allowing to overtake current lower priority interrupt which is in stacking process.

These features are handled automatically and you don’t have to care much about this – just enjoy faster ISR response.

STM Cortex-M3 interrupt system

During microcontroller initialization (when start-up code is run) all exception/interrupt vectors usually are stored in very beginning of flash memory starting from address 0×00000004. Address 0×00000000 is used to store initial stack pointer value.

As you can see in table, first 15 interrupts are generated within cortex core while other down the list are interrupts generated by peripherals like pins, timers, ADC, DMA, etc. STM32F103ZET6 NVIC is able to handle up to 60 maskable interrupt channels plus 16 lines of core interrupts. Each interrupt (except first three: Reset, NMI, Hard fault) can have 16 priority levels set with 4 bits in 8-bit priority level register. The lover number means higher priority. The higher priority may preempt lower priority automatically. Priority bits may be split in to two groups called Preemptive priority and sub-priority. This doesn’t change much, but helps to organize priorities so that same preemptive level priorities could be arranged in to sub-priorities in order to decide which should be handled first. Anyway all this is done with same 4- bits what leads to total number of 16.

The whole procedure of enabling interrupts consists of following steps:

  1. Select interrupt channel in NVIC module;
  2. Set preemptive priority;
  3. Set sub-priority;
  4. Enable interrupt for particular line.

Then you have to take care of interrupt service routine where your code will be performed when interrupt occurs.

EXTI and pin mapping

External interrupts from microcontroller pins aren’t traced directly to NVIC as you’d expect. STM32 provides flexible mechanism that allows mapping different pins to same channel. This gives lots of freedom to decide on which pin to generate interrupt on which channel. So external interrupts are manged through External Interrupt/event Controller (EXTI). EXTI can be set to rise event on rising, falling or both edges. There are 19 lines in EXTI that are associated with mapped pins and other sources. 16 lines are dedicated to port pins each line for separate pin number like this:

Other three lines are dedicated to RTC alarm interrupt, power voltage detect (PVD) and USB wakeup event. Then these lines are traced to NVIC controller in following manner:

  • EXTI0 to EXTI4 are traced directly to NVIC as separate channels;
  • EXTI5 to EXTI9 are grouped to single NVIC channel (EXTI5_9);
  • EXTI10 to EXTI15 are grouped to single NVIC channel (EXTI10_15);
  • RTC alarm, PVD and USB wakeup are also traced as single separate channels in NVIC.

Some practical examples

Having this information we can start building our code. In our development board buttons are connected as follows:

Each of them accidentally (or maybe not) falls in to positions where each of them can be mapped to different EXTI lines that allows to have dedicated NVIC channels. This way we will be able to write separate separate handlers for each button:

  • EXTI0 line for WAKEUP button (EXTI0_IRQHandler);
  • EXTI3 line for USER2 button (EXTI3_IRQHandler);
  • EXTI9 line for USER1 button (EXTI9_5_IRQHandler;
  • EXTI13 line for TAMPER button (EXTI15_10_IRQHandler;

We are going to write simple routine where each button will toggle related LED. To set up buttons for generating interrupts we write following ButtonInitEXTI() function:

void ButtonsInitEXTI(void){//enable AFIO clockRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);EXTI_InitTypeDef EXTI_InitStructure;//NVIC structure to set up NVIC controllerNVIC_InitTypeDef NVIC_InitStructure;//GPIO structure used to initialize Button pins//Connect EXTI Lines to Button PinsGPIO_EXTILineConfig(BWAKEUPPORTSOURCE, BWAKEUPPINSOURCE);GPIO_EXTILineConfig(BTAMPERPORTSOURCE, BTAMPERPINSOURCE);GPIO_EXTILineConfig(BUSER1PORTSOURCE, BUSER1PINSOURCE);GPIO_EXTILineConfig(BUSER2PORTSOURCE, BUSER2PINSOURCE);//select EXTI line0EXTI_InitStructure.EXTI_Line = EXTI_Line0;//select interrupt modeEXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//generate interrupt on rising edgeEXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//enable EXTI lineEXTI_InitStructure.EXTI_LineCmd = ENABLE;//send values to registersEXTI_Init(&EXTI_InitStructure);//select EXTI line13EXTI_InitStructure.EXTI_Line = EXTI_Line13;EXTI_Init(&EXTI_InitStructure);EXTI_InitStructure.EXTI_Line = EXTI_Line3;EXTI_Init(&EXTI_InitStructure);EXTI_InitStructure.EXTI_Line = EXTI_Line8;EXTI_Init(&EXTI_InitStructure);//disable AFIO clockRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,DISABLE);//configure NVIC//select NVIC channel to configureNVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//set priority to lowestNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;//set subpriority to lowestNVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;//enable IRQ channelNVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//update NVIC registersNVIC_Init(&NVIC_InitStructure);//select NVIC channel to configureNVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;NVIC_Init(&NVIC_InitStructure);}

It may seem a bit complicated but in deed this is simple when you know what you’re doing. Just a quick overview of what’s done. First of all when modifying/using some peripheral don’t forget to enable bus clock for or otherwise you’ll end up wandering why it’s not working when settings seems to be OK. So are going to be used as alternate functions this is why we need to enable AFIO bus clock. Then we simply map button pins to adequate EXTI lines with GPIO_EXTILineConfig() function which sets proper bits in AFIO->EXTICR registers. Then we select Interrupt mode for EXTI lines (there can be software events also). Generate interrupts on falling edge and with these settings enable current EXTI line. This has to be done with each line.

Once EXTi lines are configured we can disable AFIO bus clock and proceed to NVIC settings. Here we are setting priorities and sub-priorities for each channel and enabling each of them one by one. This is it. Now we can implement interrupt handlers that we are gonna place in separate source file (stm32f10x_it.c). here we implement codes:

void EXTI0_IRQHandler(void){//Check if EXTI_Line0 is assertedif(EXTI_GetITStatus(EXTI_Line0) != RESET){LEDToggle(1);}//we need to clear line pending bit manuallyEXTI_ClearITPendingBit(EXTI_Line0);}

and so on for all channels. Within handler it is good practice to check if current EXTI line is asserted. Then we can do our business like toggle LED. And before leaving EXTI handler it is important t oreset EXTI line as it stays set until manually cleared. If not this line will generate chain interrupts constantly as NVIC takes this as pending interrupt all the time.

Finally we can write our main code which is actually nothing much left:

//STM32F103ZET6 Buttons Test#include "stm32f10x.h"#include "leds.h"#include "buttons.h"#include "stm32f10x_it.h"int main(void){//init ledsLEDsInit();//init buttons t ogenerate interruptsButtonsInitEXTI();//start sys tick timer that also generates interruptsSysTick_Config(15000000);while (1){//your tasks}}

all we need is to implement LED pins, Initialize buttons by calling ButtonsInitEXT() function and thats it. To show another interesting feature of Cortex microcontroller I also enabled SysTick timer which simply generates SysTick interrupts every second.

void SysTick_Handler(void){LEDToggle(5);}

Interrupt handler simply toggles LED5.

[via: http://www.scienceprog.com/]

 

New development board have just arrived. Thought it would be nice to push things more towards ARM cortex-M3 playground.

This a STMicroelectronics STM32F103ZET6 ARM Cortex – M3 MCU based development board with 3.2” Touch LCD screen. This is a high – density performance line 32 -bit MCU featuring internal 512K of FLASH memory, 64K of RAM. It is rich in peripherals like USB, CAB, 11 timers, 3ADC and bunch of communication interfaces. Microcontroller itself seems to be powerful enough to run quite intense tasks, but there are more memory populated on board. Additionally there are:

  • 512K SRAM module;
  • 2M NOR FLASH;
  • 28 NAND FLASH;
  • 2M serial Flash;
  • 2K 24LC02 EEPROM;
  • 2xSD card slots (on board and on LCD expansion).

There also is a high speed CAN transceiver MCP2551chip with connector for easy access. Also there are two channels of USART populated, RS485, USB, beeper, 5 LEDs, 4 keys, 3 ADC, 2 PWM and 2 DAC screw terminals. Board can be powered from several sources selected by jumpers: external 5V, USB power or JLink power.

All MCU pins are populated through standard pitch leads 2.54mm.

This wouldn’t be fun without 3.2” color LCD with touch screen.

Board came with preloaded demo software that demonstrates μC/GUI capabilities. There are some attempts to port ulinux for this board as well. Right now I would like to set up FreeRTOS port for it and do some initial demos.

If you are looking for one – you can get them really cheap from ebay.

[via: http://www.scienceprog.com/]

 

SMD has entered hobby market long time ago, but there are still many people who afraid to push their projects to SMT level. Once you try it appears to be very easy – even easier than through hole PCB technology. Dave from eevblog have published series of PCB soldering tutorials where he goes through tools needed to make quality soldering, then through hole soldering tips and finally SMD component soldering.

In this video Dave carefully explains what main techniques (individual pin soldering, well based and drag) can be used to successfully solder SMD parts and what odds are awaiting for inexperienced players. If you don’t want to solder with iron, then you’ll see how it is easy to do this with solder paste and hot air gun.

So, take your time and see how it’s easy.

[via: http://www.scienceprog.com/]

 

Last time we have made a good starting point with setting up a project template for STM32F103ZET6 development board using GNU tools. Using same project template we can move forward and start programing other elements. This time a quick note about adding button library. This is really modest implementation which simply initializes port pins and then reads their status.

Development board is equipped with four user programmable buttons named WAKEUP, TAMPER, USER1 and USER2. We are not going to care about meaning of names just use them as general purpose buttons for now.

For this we just need to create another pair of driver files buttons.c and buttons.h. In buttons.h file we simply define button ports and pins with some friendly names. Also as well we have to think about clocking proper peripheral buses.

#define BWAKEUPGPIO_Pin_0#define BWAKEUPPORTGPIOA#define BWAKEUPPORTCLKRCC_APB2Periph_GPIOA#define BTAMPERGPIO_Pin_13#define BTAMPERPORTGPIOC#define BTAMPERPORTCLKRCC_APB2Periph_GPIOC#define BUSER1GPIO_Pin_8#define BUSER1PORTGPIOA#define BUSER1PORTCLKRCC_APB2Periph_GPIOA#define BUSER2GPIO_Pin_3#define BUSER2PORTGPIOD#define BUSER2PORTCLKRCC_APB2Periph_GPIOD

Next step is button initialization. In buttons.c we simply create function:

void ButtonsInit(void){//GPIO structure used to initialize Button pinsGPIO_InitTypeDef GPIO_InitStructure;//Enable clock on APB2 pripheral bus where buttons are connectedRCC_APB2PeriphClockCmd(BWAKEUPPORTCLK|BTAMPERPORTCLK|BUSER1PORTCLK|BUSER2PORTCLK,ENABLE);//select pins to initialize WAKEUP and USER1 buttonsGPIO_InitStructure.GPIO_Pin = BWAKEUP|BUSER1;//select floating input modeGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//select GPIO speedGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(BWAKEUPPORT, &GPIO_InitStructure);//select pins to initialize TAMPER buttonGPIO_InitStructure.GPIO_Pin = BTAMPER;GPIO_Init(BTAMPERPORT, &GPIO_InitStructure);//select pins to initialize USER2 buttonGPIO_InitStructure.GPIO_Pin = BUSER2;GPIO_Init(BUSER2PORT, &GPIO_InitStructure);}

Here we have to enable peripheral clocks for used ports with RCC_APB2PeriphClockCmd command. Then we can start setting up port pins. According to peripheral library we need to do this through structure variable where each field caries particular setting. These would be GPIO_Pins (all pins set for same port), then GPIO_Mode – we set it as input floating, and GPIO_Speed as max. Buttons aren’t connected to same port so we have to do initialization separately for each port with GPIO_Init function.

Lastly we write simple function that reads button state.

uint32_t ButtonRead(GPIO_TypeDef* Button_Port, uint16_t Button){return !GPIO_ReadInputDataBit(Button_Port, Button);}

When pressed, buttons pulls port pin low so GPIO_ReadInputDataBit() function returns ’0′. Probably it is more logical to have ’1′ on click so we used NOT ‘!’operator to do so. And here is a simple demo code which lights different LED on each button press. Code still runs in super loop so don’t judge code efficiency its only for demonstration.

//Buttons Test#include "stm32f10x.h"#include "leds.h"#include "buttons.h"//delay functionvoid Delay(__IO uint32_t nCount){for(; nCount != 0; nCount--);}int main(void){//init ledsLEDsInit();ButtonsInit();while (1){//read Wakeup buttonif (ButtonRead(BWAKEUPPORT, BWAKEUP)){//led 1 onLEDOn(1);//delayDelay(500000);//led 1 offLEDOff(1);}//read TAMPER buttonif (ButtonRead(BTAMPERPORT, BTAMPER)){//led 2 onLEDOn(2);//delayDelay(500000);//led 2 offLEDOff(2);}//read User1 buttonif (ButtonRead(BUSER1PORT, BUSER1)){//led 3 onLEDOn(3);//delayDelay(500000);//led 3 offLEDOff(3);}//read User2 buttonif (ButtonRead(BUSER2PORT, BUSER2)){//led 4 onLEDOn(4);//delayDelay(500000);//led 4 offLEDOff(4);}}}

In real applications buttons check should be interrupt based. But we will get to that soon.

Project source code[420KB]

[via: http://www.scienceprog.com/]

 

FreeRTOS is known as Real Time Operating System. Probably it would be too dare call it real-time-os, rather a real time scheduler where applications can be split in to independent tasks that share full processor resources by switching them rapidly it looks like all tasks are executed in parallel. This feature is called multitasking.

There are lots of debates on using RTOS on AVR microcontrollers as they are arguable too small for running scheduler. The main limitation is small amount of ram and increased power usage. If you are gonna use lots tasks in application, probably you will run out of ram that is used for saving context when switching between tasks. Consider FreeRTOS only if you use larger scale AVRs like Atmega128 or Atmega256. Surely you can find smaller schedulers that are specially designed for smaller microcontrollers even tiny series. In other hand if you master FreeRTOS it can be used with multiple types of microcontrollers like ARM, Cortex, PIC and multiple compilers including IAR, GCC, Keil, Rowley, Attolic. And main reason to keep eye on it – its free.

Probably it would take lots of time and space to go through RTOS theory. Some great information can be found on FreeRTOS website itself. In this series of posts we are going to focus on practical side of using RTOS on AVR microcontroller. We will go through several steps from single task application to more complex solutions.

Things needed to start with FreeRTOS

To start using FreeRTOS we need to download it from http://www.freertos.org/. While writing this post latest version was FreeRTOSV7.0.1. In downloaded package you’ll find freertos source code files, ports to specific microcontrollers and lots of example programs for various microcontrollers and compilers. We are going to use old good Piconomic Atmega128L development board with externalmemory expansion board that adds additional 8K of SRAM. You can chose any Atmega128 development boardas far as it can blink LEDs, read buttons and use USART. Programs will work fine on any of them. As programming environment we are going to use AVRStudio5 which is still quite new and capricious. If you want to learn how to start working with AVRStudio5, check out this short tutorial.

Preparing AVRStudio5 project

First of all we create new project in AVRStudio5. For this we simply File->New Project and select AVR GCC C Executable Project. Enter proper location where your project will be stored.

Click OK. Then select DeviceAtmega128” from device list:

Click OK and yo are set up with basic project with main program file that contains some initial code. As FreeRTOS package contains lots of files that we don’t need for our project we are going to copy necessary files to our folder. To make it easier to update FreeRTOS files with upcoming releases we are going to maintain folder structure close to original. To do so in out project tree we are going to create Source folder. To do so just click right mouse button on project folder and select Add->New Folder and type in Source. Now import following files to Source folder from downloaded FreeRTOS package Source folder:

add all files that are in Source directory (including readme.txt). Adding files is simple – just click right mouse button of Source folder and select Add->Existing Item and in file browser select necessary files (multiple select is possible!).

We have added only kernel C files. Now we have to take care of headers. For this we need to create include folder inside Source folder. Then add all files to it from FreeRTOS package include folder.

Now that we’ve taken care of FreeRTOS kernel we need port files. As you may know, port files are to support specific microcontroller hardware. Port files contain information on how to run SysTick timer and how to save and restore context to and from task. Porting is essential part if wee need to support one or another microcontroller. FreeRTOS package already has lots of port options and mos likely you may find one that will support your selected MCU. In other case you’ll have to write port by your own. As we are using Atmega128L microcontroller seems that included Atmega323 port works fine so we are going to use it for now. To include port files properly lest create folder named portable inside Source folder. And then in portable folder we create GCC folder. And in GCC we create folder named ATMega323. Then import porting files port.c and portmacro.h to this folder from FreeRTOS package. Still this isn’t finished with files. We also need memory management file heap_1.c, which takes care of allocating and freeing memory for tasks and queues. To add this file to project create MemMang folder in portable folder and add file from same folder in downloaded package. And lastly FreeRTOS needs FreeRTOSConfig.h configuration file that keeps all freeRTOS related settings. Just import it from FreeRTOS\Demo\AVR_ATMega323_WinAVR.

To make things neat lets create another folder Drivers in project root directory. This will be used to store microcontroller peripheral drivers like USART, I2C, ADC, button, LED and so on.

Before we are going to write some code, project has to be configured. To start configuration just go to menu Project->Properties. First go to Build tab.

This time we are going to configure project as release. Select Configuration as Release. So wee need to generate .hex file (.map, .lss and .eep). These can be selected in Build Artifact group.

In Toolchain tab and Optimization select -Os optimization. And in Directories you will need to include all directories containing .h files in your project(I only managed to get working only with absolute paths). Add GCC_MEGA_AVR in Defined Symbols to tell core that we are going to use GCC for AVR microcontroller.

FreeRTOS Configuration

FreeRTOS has several options that allow to configure applications for various needs. All predefined parameters are placed in FreeRTOSConfig.h file.Depending on what functions are you gonna use some of them may be omitted. AVR microcontroller is too small to use all features of RTOS because of limited RAM. For instance using trace facility probably would be killing. So for our basic example we are using following settings:

#define configUSE_PREEMPTION1#define configUSE_IDLE_HOOK0#define configUSE_TICK_HOOK0#define configCPU_CLOCK_HZ( ( unsigned long ) 7372800 )#define configTICK_RATE_HZ( ( portTickType )1000 )#define configMAX_PRIORITIES( ( unsigned portBASE_TYPE ) 1 )#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 85 )#define configTOTAL_HEAP_SIZE( (size_t ) ( 3500 ) )#define configMAX_TASK_NAME_LEN( 8 )#define configUSE_TRACE_FACILITY	0#define configUSE_16_BIT_TICKS1#define configIDLE_SHOULD_YIELD1#define configQUEUE_REGISTRY_SIZE	0/* Co-routine definitions. */#define configUSE_CO_ROUTINES0#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )/* Set the following definitions to 1 to include the API function, or zeroto exclude the API function. */#define INCLUDE_vTaskPrioritySet0#define INCLUDE_uxTaskPriorityGet0#define INCLUDE_vTaskDelete0#define INCLUDE_vTaskCleanUpResources	0#define INCLUDE_vTaskSuspend0#define INCLUDE_vTaskDelayUntil1#define INCLUDE_vTaskDelay0

We are going to use preemptive kernel engine where kernel timer tick ISR determines which task should run next according to task priorities. Preemptive multitasking is similar to OS like Linux or Windows. Preemptive kernel uses more RAM but is more flexible. Also we aren’t going to use idle hook for now – so disable it too and make idle task yield immediately once it is run. We won’t be changing task priorities during program flow so we disable this functionality too. We are going to use task delay utilities so leave them ON.

Each functionality that isn’t uses frees some amount of memory. For low memory devices is very important to select these carefully.

After all project properties are set, we can start coding our first application. Why not to start with single task – LED blink. To make code modular we will start with writing LED library. So we need to write these routines and put in separate .c and .h files.

LED freeRTOS driver

We created a Drivers folder in our project rood directory. Simply create LED.c and LED.h files by pressing right mouse button on Drivers folder and selecting Add->New Item. AVRStudio5 will generate .c and .h templates where we can start writing our code.

We are going to control one LED connected to pin D6 in our test project. Writing driver is easy. First we need to initialize LED pin as output with simple function:

void vLEDInit(void){// Set LED_O as output pinDDR_LED_O |= (1<<BIT_LED_O);}

and then write LED toggle function that will be called by task.

void vLEDToggle(void){//Toggle LEDPORT_LED_O ^= (1<<BIT_LED_O);}

that’s it.

Creating task

Later we are going to add more tasks so let’s put them all in one separate source file. I created mytasks.c file along with mytasks.h. Lets create simple tasks which will toggle LED every one second. We already have LED toggling driver ready. The only thing left is managing proper delay so LED would toggle every second. FreeRTOS has handy function that allows to set tasks delays when tasks should run. This is called vTaskDelayUntil(). It takes two parameters – previous wake time and ticks to wait. Now its a tricky part of all this. If you look back in FreeRTOSConfig.c file you’ll find a line:

#define configTICK_RATE_HZ( ( portTickType )1000 )

which means that kernel timer ticks every 1ms. In order to get 1s delay we need to wait 1000 ticks. All we need is to set this number as second parameter.

void vLEDFlashTask( void *pvParameters ){vLEDInit();portTickType xLastWakeTime;const portTickType xFrequency = 1000;xLastWakeTime=xTaskGetTickCount();for( ;; ){vLEDToggle();vTaskDelayUntil(&xLastWakeTime,xFrequency);}}

Function xTaskGetTickCount() returns current number of ticks calculated form program start. So we need to pass this number to our delay function as first parameter. We are doing LED initialize before endless for(;;) loop. And task application goes inside endless loop. Here goes our vLEDToggle() function and vTaskDelayUntil() function. vtaskDelayUntil function ensures that task remains in blocked state until delay ends. So this means that blocked task isn’t scheduled until proper event unblocks it (in our case delay exceeds). If we would use idle task hook function for setting MCU to power save mode our application would require less energy as your task is run only every 1s.

Running freeRTOS task

Once task is create consider biggest job is done. Now what is left is to create this task in main routine and start scheduler. Before we start we must decide what priority task should be assigned with. As we are going to use one task (plus idle) we can use idle priority:

#define mainLED_TASK_PRIORITY( tskIDLE_PRIORITY )

To create task we are gonna use one handy function xTaskCreate(). It needs several parameters. First one is task function name that has to be run. Second is a task name that can be freely chosen. Third parameter is stack size. Our application is very simple so minimal stack can be used. For more complex tasks select this parameter carefully. Then follows pointer to parameters that has to be passed to tasks. If there is no parameters to pass use NULL. Following parameter is task priority. And last parameter is used to pass back a handle by reference so task could be addressed. Pass NULL as we aren’t going to use it. Our created task should look as follows:

xTaskCreate( vLEDFlashTask, ( signed char * ) "LED", configMINIMAL_STACK_SIZE, NULL, mainLED_TASK_PRIORITY, NULL );

And lastly we must start scheduler which is our rtos kernel. This is done by calling vTaskStartScheduler().

Compiled project occupies about 6K of Flash memory and uses 3,6K(88.5%) of RAM. So RAM is limiting factor on how many tasks are you gonna run and what complexity they are. If no preemption is required as alternative co-routines can be used as they can share stack.

You can download full project here: M128RTOS[~200K]

[via: http://www.scienceprog.com/]

© 2011 Geko Geek This is a news aggregator website. Articles and images are copyrighted to their original source authors. Gekogeek takes no responsibility about the articles content Suffusion theme by Sayontan Sinha