stm32l programming

// two ways to enable clock for port A:

// include name depends on controller
// set up a bit in control register to enable clock port A
#include “stm32l1xx.h”
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
// this way uses only CMSIS library

// second way is a function call which wraps around a first way
#include “stm32l1xx_rcc.h”
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA , ENABLE);
// this way uses standard peripherial library
// note that typical style is not to include “stm32l1xx_rcc.h” directly,
// but instead create project-specific “stm32l1xx_conf.h” file, put include in that file,
// and also define USE_STDPERIPH_DRIVER macro. This way will set stm32l1xx.h to include
// mentioned _conf.h, which, in turn, includes _rcc.h

——————————————–
// two ways of configuring legs 8 and 9 or port B for output in push-pull mode:

#include <stm32l1xx_gpio.h>

// direct write to registers
// requires only CMSIS library (only header “stm32l1xx.h” )

// Each general-purpose I/O port has four 32-bit configuration registers (GPIOx_MODER,
// GPIOx_OTYPER, GPIOx_OSPEEDR and GPIOx_PUPDR), two 32-bit data registers
// (GPIOx_IDR and GPIOx_ODR), a 32-bit set/reset register (GPIOx_BSRR), a 32-bit locking
// register (GPIOx_LCKR) and two 32-bit alternate function selection register (GPIOx_AFRH
// and GPIOx_AFRL).

// GPIOB is a constant of type GPIO_TypeDef, mapped to special address.
// Similar constants are for A and C

// “output” mode means value “01” in corresponding MODER
// 10 – alternate function, 00 – input
GPIOB->MODER |= GPIO_MODER_MODER8_0
GPIOB->MODER &= ~GPIO_MODER_MODER8_1

GPIOB->MODER |= GPIO_MODER_MODER9_0
GPIOB->MODER &= ~GPIO_MODER_MODER9_1

// for output and alternate function it is possible to specify open drain or push-pull.
// input always imply push-pull
// if bit is set for pin, then it is open drain
GPIOB->OTYPER |= GPIO_OTYPER_OT_9
// if bit is reset for pin, then it is push-pull
GPIOB->OTYPER &= ~GPIO_OTYPER_OT_9

// for all modes we can specify if it is floating, push up or pull down.
// values are 00 – floating, 01 – push up, 10 – pull down
// following example is for pull down
GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR9_0
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR9_1
// following example is for push up
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR8_0
GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR8_1
// A better way: modify bits via function.
// requires standard periph driver

// declare and init structure
GPIO_InitTypeDef PORT;
GPIO_StructInit(&PORT);
// Specifies mode and speed for a set of pins.
PORT.GPIO_Pin = (GPIO_Pin_9 | GPIO_Pin_8);
PORT.GPIO_Mode = GPIO_Mode_Out_PP;
PORT.GPIO_Speed = GPIO_Speed_2MHz;
// set value for specified port
GPIO_Init( GPIOB , &PORT);

——————————————–
many ways of setting level 1 on legs 8 and 9 of port C:

// direct write to ‘value’ register of port C.
// get a value, use or-mask to set pins, then write a new value
GPIOC->ODR |= (GPIO_ODR_ODR9 | GPIO_ODR_ODR8);

// write a “set” command to set-reset register of port C.
GPIOC->BSRR=(GPIO_BSRR_BS8|GPIO_BSRR_BS9);

// via functions
// set several bits to 1
// either this way
GPIO_SetBits(&GPIOC, GPIO_Pin_9 | GPIO_Pin_8);
// or this way
GPIO_WriteBit(&GPIOx, GPIO_Pin_9 | GPIO_Pin_8, Bit_SET);

——————————————–
two ways of setting level 0 on legs 8 and 9 of port C:

// direct write to ‘value’ register of port C.
// get a value, use and-mask to clear pins, then write a new value
GPIOC->ODR &= ~(GPIO_ODR_ODR9 | GPIO_ODR_ODR8);

// write a “reset” command to set-reset register of port C.
GPIOC->BSRR=(GPIO_BSRR_BR8|GPIO_BSRR_BR9);

// via functions
// either this way
GPIO_ResetBits(GPIOC, GPIO_Pin_9 | GPIO_Pin_8);
// or this way
GPIO_WriteBit(&GPIOx, GPIO_Pin_9 | GPIO_Pin_8, Bit_RESET);

———————————————-
reading input data via functions

uint8_t GPIO_ReadInputDataBit(GPIOA, uint16_t GPIO_Pin);

——————————————–
Choosing correct alternate function for pin

// first, see above hot to configure a pin by setting MODER to AF (value 10)

// Each pin has several alternate functions. It depends on pin, and on controller
// theoretically up to 16 functions are available. In practice only 2-4 values are used.
// for each port (A, B, C) there is a 64-bit AF register, represented as two 32-bit parts.
// GPIOx_AFRL and GPIOx_AFRH. Each pin has 4 bits in this register.
// So bits for pins 0 – 7 are in GPIOx_AFRL, and bits for pins 8 – 15 are in GPIOx_AFRH
// To understand which pin has which possible values for bits, see datasheet.
// functional way
// for example, pin 6 of port B has timer TIM4 channel1 attached to alternate function 2.
// TIM4 has 4 channels, each attached to different pin. However, all those channels
// are mapped using same alternate function number for each pin, so this alternate
// function is just called ‘GPIO_AF_TIM4’

GPIO_PinAFConfig(&GPIOB, GPIO_Pin_6, GPIO_AF_TIM4);

——————————————–
Configuring timer TIM2:

// first, don’t forget to attach timer to system clock on application bus 1
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

// each timer has a counter. This counter increments with every timer tick
// it is possible to control a speed of the tick, and a value of counter
// there is also a built-in capability of auto-reset for counter

// prescaler: a divider for system frequency.
// Specifies how fast timer ticks (and counter increments)
TIM2->PSC = 0x00A7;

// auto-reload register. Specifies a value after which timer counter resets
TIM2->ARR = 0x0FFF;
// a frequency of timer reset = sys_freq/[prescaler*(ARR + 1)].

// to start a timer an ‘enabled’ bit should be set in control register CR1
TIM2->CR1 |= TIM_CR1_CEN;

// get a value of counter
TIM2->CNT

——————————————–
Configuring timer TIM2 for capture and compare:

// each timer has several channels, each channel is connected to some output pin
// channels are configured independently

// specify capture and compare value for channel 3
TIM2->CCR3 = 0x050;

// capture and compare mode registers control channels 1,2 (reg CCMR1) 3,4 (reg CCMR2)
// for each channel there are 3 ‘mode’ bits, and they could be set-reset independently
// however, they together specify capture and compare mode.
// following example configures channel 3 and sets bits to 110, which means PWM
// PWM means ‘if TIM2->CNT < TIM2->CCR then out_1 else out_0’
TIM2->CCMR2 |= TIM_CCMR2_OC3M_1|TIM_CCMR2_OC3M_2;
TIM2->CCMR2 &= ~TIM_CCMR2_OC3M_0;

// capture and compare enable register (one for each timer) specifies if use CC for channels
// this example enables capture and compare for channel 3 of timer TIM2
TIM2->CCER |= TIM_CCER_CC3E;
——————————————–
My project: use PWM to control brightness of LED

# Part 1, choosing modules and calculations.

0. Choose brighness. Let b = 50%
1. Find a pin to which LED is connected
2. Find a port for a pin
3. Find if a pin has some timer channel as alternate function.
4. Choose a frequency of PWM. Let f = 1 kHz
5. Let timer’s ARR = 100 – 1, so each tick of timer is 1% of whole period
6. Now we can calculate prescaler.
f = sys_freq/[prescaler*(ARR + 1)]
prescaler = sys_freq/[f*(ARR + 1)] = 24M/[1k*100] = 240

# Part 2, programming

7. Enable system clock for choosen IO port and choosen timer.
8. configure a timer with prescaler and auto-reload register (TIM?->ARR)
9. specify capture-and-compare register for choosen channel with value of b (brightness)
10. for choosen channel find corresponding CCMR register (1 or 2)
and set bits for PWM (bits 2 and 1 are enabled, bit 0 is disabled)
11. configure a pin for output (any frequency) via alternate function, push-pull
12. configure timer as an alternate function for pin
13. Enable CCM for chosen channel via bit in timer’s CCER
14. Enable timer via bit in timer’s CR

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: