You are on page 1of 8

École Centrale de Nantes

FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

All authorized documents.

This exam has 8 pages.

4 independent exercises

The answers must be written within the boxes

Exercise 1 Exercise 2 Exercise 3 Exercise 4 Total

3 3 7 7 20

Name Prenom Nom

Important note: We consider that:


• clocks for all the peripherals are set :RCC->xxx for both GPIO and timers

• Reset of peripherals that require it has been done (RCC->APB1RSTR).

• the MCU and peripheral clocks are set to 64 MHz.

• Functions of the pinaccess.h header file are available:


1 int pinMode ( port , numBit , mode );
2 void digitalWrite ( port , numBit , value );
3 void digitalToggle ( port , numBit );
4 unsigned char void digitalRead ( port , numBit );
5 unsigned char pinAlt ( port , numBit , AFId );

1
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

Exercise 1: conversions (3 points)


Q 1 (2 pt.) Give the value of val in line 4 and 8

1 uint16_t val = 0 xfabd ;


2 val = val & 0 x5932 ;
3

4 // val = >
5

6 val = val | 0 x550 ;


7

8 // val = >
————————————————————
Q 2 (1 pt.) Give the value of val2 in line 4

1 short int val2 = 0 x5DF0 ;


2 val2 = ( val2 & ∼ (0 x7 < <4)) | (0 x2 < <4) ;
3

4 // val2 = >

Exercise 2: Bit setting (2 points)


We need a function that sets a bit of an integer. The function prototype is:

uint32_t bitSet(uint32_t value, int bitNumber);


where:
• value is the input value;
• bitNumber is the bit number that should be set in value, from 0 (lsb) to 31 (msb)
• the output of the function: value updated with the bit bitNumber set.
Q 3 (1 pt.) What will be the result of the following code (the value of val):

1 uint32_t val = bitSet (123456 , 10);

Q 4 (2 pt.) Give the code for this function:

1 uint32_t bitSet ( uint32_t value , int bitNumber )


2 {
3

8 }

2
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

Exercise 3: Chess clock (11.5 pts)


The objective of this exercise is to define a clock for the chess game. The hardware part has:

• 3 buttons

– player 1 on PA0
– reset on PA1
– player 2 on PA2

• one LCD screen

• one led on PA3

As defined in Wikipedia: A chess clock consists of two adjacent clocks with buttons to stop one clock
while starting the other, so that the two clocks never run simultaneously. Chess clocks are used in
chess and other two-player games where the players move in turn. The purpose is to keep track of
the total time each player takes for their own moves, and ensure that neither player overly delays
the game.
At the startup, or when the reset button is pushed, the remaining time for each player is 90 minutes.
A short example with a run:

• at startup, the remaining time for each clock is 90 minutes and both clocks are stopped.

• player 1 pushes is button to start the game

• the remaining time for player 2 starts to decrement, second after second.

• when the player 2 has played, he pushes his button: its clock is stopped and the player 1’s
clock starts to decrement.

• and so on. . .

• if one clock gets to 0, the led is ON.

• the reset button should be pressed to restart the application.

The reset button just restarts the whole application (both clock stopped, and init at 90 minutes)
The LCD screen only displays the remaining time for each player. It’s driver has been written and
the following functions are available:

1 void lcdInit (); // init . should be called in the setup ()


2 // print the remaining time for player 1 ( minutes , seconds )
3 void lcdPrintP1 ( uint8_t min , uint8_t sec );
4 // print the remaining time for player 2 ( minutes , seconds )
5 void lcdPrintP2 ( uint8_t min , uint8_t sec );

We will use only one timer for the application (timer TIM6). The internal minimal resolution is
100ms, even if the displayed value will be in seconds. The buttons will use a software Finite State
Machine (FSM), and no interrupt. The FSM for the 3 buttons is already implemented throught the
function (you don’t have to implement it again).

1 enum PBState { OFF , PUSH , ON , RELEASE };


2

3 /* return the state of the buttons :


4 * x in [0 ,2] for the button on PAx
5 */
6 enum PBState managePushButton ( int x );

3
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

Q 5 (2.5 pt.) Give the initilization of the hardware parts: timer (with interrupt), I/O.

1 void setup ()
2 {
3 lcdInit ();
4 pinMode ( PORTA ,0 , INPUT_PULLUP );
5 pinMode ( PORTA ,1 , INPUT_PULLUP ); // 1 if io ok
6 pinMode ( PORTA ,2 , INPUT_PULLUP ); // -.5 if no pullup
7 pinMode ( PORTA ,3 , OUTPUT );
8

9 TIM6 - > PSC = 64000 -1; // 1 timer


10 TIM6 - > CR1 |= TIM_CR1_CEN ;
11 TIM6 - > ARR = 100 -1; // each 100 ms
12 TIM6 - > CNT = 0;
13

14 TIM6 - > DIER |= TIM_DIER_UIE ; // .5 it .


15 NVIC_EnableIRQ ( TIM6_DAC1_IRQn );
16 }

We define a Finite State Machine (FSM) that can define the different states of the system: RESET
(init), PLAYER1 (clock of player 1 is running), PLAYER2 (clock of player 1 is running), END (no more
time). . . as in slide 113 of the lecture slides.
Q 6 (3 pt.) Define (graphically) the FSM of the application (give information about the transitions).
Some transitions will be perfomed under interrupt, and other in the main loop. Make a difference
with theses transitions (color).

RESET
push PA1 push PA1

push PA2
push PA0

push PA0

PLAYER2 push PA1 PLAYER1

push PA2

time elapsed
time elapsed

END

Q 7 (5 pt.) Give the full implementation of the chess clock (next page).

4
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

1 // Chess Clock states


2 enum CCState { RESET , PLAYER1 , PLAYER2 , END };
3 volatile enum CCState state ;
4

5 volatile int remaining_pl1 = 0; // 1 pt


6 volatile int remaining_pl2 = 0; // in 100 ms
7

8 int main ()
9 {
10 enum PBState PB_Pl1 , PB_Reset , PB_Pl2 ;
11 setup ();
12 while (1)
13 {
14 // buttons
15 PB_Pl1 = managePushButton (0);
16 PB_Reset = managePushButton (1);
17 PB_Pl2 = managePushButton (2);
18 // main FSM
19 switch ( state ) // FSM 1.5 pt
20 {
21 case RESET :
22 remaining_pl1 = remaining_pl2 = 90*60*10;
23 if ( PB_Pl1 == PUSH ) state = PLAYER2 ;
24 if ( PB_Pl2 == PUSH ) state = PLAYER1 ;
25 break ;
26 case PLAYER1 :
27 if ( PB_Pl1 == PUSH ) state = PLAYER2 ;
28 lcdPrintP1 ( remaining_pl1 /600 , remaining_pl1 %600); // lcd : 1 pt
29 break ;
30 case PLAYER2 :
31 if ( PB_Pl2 == PUSH ) state = PLAYER1 ;
32 lcdPrintP2 ( remaining_pl2 /600 , remaining_pl2 %600);
33 break ;
34 case END :
35 if ( PB_Reset == PUSH ) state = RESET ;
36 break ;
37 }
38

39 }
40 }
41

42 void TIM6_DAC1_IRQHandler () // each 100 ms


43 {
44 // Ack .5 pt
45 TIM6 - > SR &= ∼ TIM_SR_UIF ;
46 // FSM 1 pt + led .5
47 if ( state == PLAYER1 ) remaining_pl1 - -;
48 if ( state == PLAYER2 ) remaining_pl2 - -;
49 if ( remaining_pl1 == 0 || remaining_pl2 == 0) {
50 state = END ;
51 digitalWrite ( GPIOA ,3 , HIGH ); // led
52 }
53 }

5
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

The increment variation (or simplified Fischer variant) consists in adding a constant time bonus
after eache move (i.e. when the player pushes his button). The bonus is 30s, and the total remaining
time can be above the initial time.
Q 8 (1 pt.) How can be implemented this feature? You can update your previous code (with another
color) or explain below how it is done.1

1 // -.5 if data corruption .


2 // between line 28 and 29:
3 remaining_pl1 += 300;
4 // Note : not between 27 and 28 , because the
5 // value may be updated in the interrupt handler !

1 Be careful of the possible data corruption!

6
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

Exercise 4: PWM Application (5.5 points)


We consider an application with only 1 led L0 connected to pin PA3. The led is driven with a PWM
signal.
Instead of blinking a led, we want its brightness to increase slowly, using a PWM signal. The time
to get from off to the full brightness should be 0.4s, with 20 intermediate steps. Then, it waits for
0.6s, and the brightness decreases to 0 in 0.4s. It waits off for 0.6s. The full cycle takes 2s.

Note: The brightness of the led L0 depends on the duty cycle of the PWM on this led.

brightness

max

0
400 1000 1400 2000 time (ms)
phase 0 1 2 3

The datasheet reports that the alternate configurations for L0 is:

port AF0 AF1 AF2 AF3 AF4 AF5 AF6 AF7 AF8 AF9 AF10 AF11 AF12 AF13 AF14 AF15
PA3 TIM2_CH4 TSC_G1_IO4 USART2_RX TIM15_CH2 EVENTOUT

Q 9 (1.5 pt.) Write the setupPWM() function that initializes the led pwm, with a duty cycle of 0%
(OFF), and a frequency of 1Khz.

1 void setupPWM () {
2 pinAlt ( GPIOA ,4 ,2); // or GPIOA ,3 ,1 = >.5 pt
3

4 // config timer .5 pt
5 TIM3 - > PSC = 64 -1; // prescaler : tick@1us
6 TIM3 - > ARR = 1000 -1; // auto - reload : counts 1000 ticks
7

8 // PWM configuration .5 pt
9 TIM3 - > CCMR1 &= ∼ TIM_CCMR1_CC2S_Msk ; // channel 2 as output
10 TIM3 - > CCMR1 &= ∼ TIM_CCMR1_OC2M_Msk ;
11 TIM3 - > CCMR1 |= 6 << TIM_CCMR1_OC2M_Pos ; // output PWM mode 1
12 TIM3 - > CCMR1 |= TIM_CCMR1_OC2PE ; // pre - load register TIM3_CCR2
13

14 TIM3 - > CR1 &= ∼ TIM_CR1_CMS_Msk ; // mode 1 // edge aligned mode


15 TIM3 - > CCER |= TIM_CCER_CC2E ; // enable
16 TIM3 - > CR1 |= TIM_CR1_CEN ; // config reg : enable
17

18 TIM3 - > CCR2 = 0; // 0%


19 }

Q 10 (1 pt.) define the main setup() function that configures timer TIM6 to generate an interrupt
each 10ms.

1 void setup () {
2 setupPWM ();

7
École Centrale de Nantes
FM EMS Prenom Nom - 8/1/2021, 10:15 – 12:15

4 TIM7 - > PSC = 64 -1; // .5 timer


5 TIM7 - > CR1 |= TIM_CR1_CEN ;
6 TIM7 - > ARR = 1000 -1; // each 1 ms
7 TIM7 - > CNT = 0;
8

9 TIM7 - > DIER |= TIM_DIER_UIE ; // .5 it .


10 NVIC_EnableIRQ ( TIM7_DAC2_IRQn );
11 }
Q 11 (3 pt.) All the code is under interrupt. Give the full code of the interrupt handler. You may use
a finite state machine and the different phases defined in the Figure (phase).

1 void TIM6_DAC1_IRQHandler () {
2 // each 1 ms .
3 TIM6 - > SR &= ∼ TIM_SR_UIF ; // .5 pt
4 static int phase = 0;
5 static int duty = 0; // duty cycle
6 static int time = 0;
7 time ++;
8 switch ( phase ) { // fsm 2 pt
9 case 0: // acc
10 if ( time % 10 == 0) { // 10 ms
11 duty += 1000/20; // 1000 steps in pwm
12 if ( duty >= 1000) {
13 duty = 999;
14 phase = 1;
15 }
16 }
17 case 1: // full
18 duty = 999;
19 if ( time > 500) phase = 2;
20 break ;
21 case 2: // dec
22 if ( time % 10 == 0) { // 10 ms
23 duty -= 1000/20; // 1000 steps in pwm
24 if ( duty <= 0) {
25 duty = 0;
26 phase = 3;
27 }
28 }
29 break ;
30 case 3: // 0
31 duty = 0;
32 if ( time >= 1000) {
33 phase = 0;
34 time = 0;
35 }
36 break ;
37 }
38 TIM3 - > CCR2 = duty ; // .5 pt
39 }
40 }

You might also like