PINS list and peripherals:
- green led: PA5
- push button (blue): PC13
- microphone: PA8
- speaker: PA9 -> TIM1_CH2
- potentiometer: PA1
- encoder: PC7 (TIM3_CH2), PC6 (TIM3_CH1)
- keyboard: PC8,9,10,11 OUTPUT (column driver), PC12,13,2,3 INPUT (row readout)
- LCD: PB12,13,14,15 as GPIO_Output, PB1,2 as GPIO_Output, PA4 as GPIO_Output
- USART2:
- Rx: PA3
- Tx: PA2
- I2C: PB9->SDA, PB8->SCL
- temperature address LM75: 0b10010000
- accelerator address: LIS2DE: 0b01010000
- SPI: (1,4 up to 42Mbps; 2,3 up to 21Mbps)
- PA5 (SCK), PA6(MISO), PA7(MOSI), PB6 (FOR LEDMATRIX: after transfer complete, SET and then RESET)
- IR: PB10 (Led attached to TIM2_CH3) and PA10 (receiver USART1RX)
Code:
HAL_GPIO_ReadPin(GPIOC_BASE, GPIO_PIN_13)
// pin PC13HAL_GPIO_WritePin(GPIOA_BASE, GPIO_PIN_5, GPIO_PIN_RESET | GPIO_PIN_SET)
// pin PA5 set or resetHAL_GPIO_TogglePin(GPIOA_BASE, GPIO_PIN_5)
// pin PA5
INTERRUPT MODE:
- set the pin to be in GPIO_EXTIx
- enable in NVIC the EXTI interrupts that include x
- check whether the interrupt routine is called on the rising or falling edge of the external event
- callback function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- inside the callback, check the origin of the GPIO interrupt with
switch (GPIO_Pin) {case GPIO_PIN_13:}
Disabling interrupts with HAL_NVIC_DisableIRQ(EXTI9_5_IRQn)
HAL_Delay(milliseconds)
generates a blocking interrupt when called. It blocks completely the microcontroller that’s why we want to avoid using it, we can use otherwise a timer.
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin)
can be used to clear the interrupt flag in the NVIC, however calling this function is bad practice.
Concurrent interrupt execution problem when they are triggered at the same time:
The
HAL_Delay(milliseconds)
generates itself an interrupt so what happens is that this interrupt and the one generated by the microphone happen at the same time. So we must clarify which one has the higher priority, otherwise if the speaker is playing, at the same time the microphone detects a loud sound and its event gets triggered again. There are different ways of handling this problem:
- In the NVIC configuration there in the upper part there is a menu called priority group that must be set to 1 bit (otherwise we cannot enable different priorities) then there is a column called pre-emption priority and we can set to 1 the interrupt that has less priority, which in this case is EXTI line [9:5] interrupts (the microphone).
- This is not enough because even if now the microphone has less priority, at the end of the entire song the pin is always checked, and since it is high it means that it has to be considered. So what we have to do in the code is at the and of the song to set the pin to 0, in order to not let the song restart again.
- Another way to do the project without using the priorities is to use a flag variable inside the code which enables the loop of playing a song changing it whenever is detected a sound by the microphone and set it at the original variable whenever the song is finished.
base timer setup: clock source = internal clock
change ARR and PSC values (by fixing one value and varying the other), to obtain the desired PWM frequency, with the formula:
using interrupt: NVIC settings -> enable global interrupt
void HAL_TIM_Base_Start_IT(&htimx);
// starts timer x with interrupt routine callbackvoid HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
// callback for timer expiring
__HAL_TIM_SET_AUTORELOAD(&htim1, arr)
//Change dynamically the content of the autoreload register__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse)
// capture and compare register, associated to the pulse__HAL_TIM_SET_COUNTER(&htim1, 0)
// resets timer counter variable
PWM (pulse width modulator) generation: the counter grows since it overflows at a certain time and it gets reset. It counts until it reaches the autoreload register (full scale range). The frequency of the PWM fpwm is defined by the ARR and the PSC because the ftim is fixed at 84 MHz.
formula:
Parameter settings:
- set pin to be active in mode TIMx_CHy (where x = timer number and y = channel of peripheral)
- set TIMx clock source as internal clock
- set TIMx channel y to be in mode "PWM Generation CHy"
- set prescaler (PSC) and counterperiod (ARR)
- set pulse of the PWM (capture and compare register) as ARR * duty cycle
HAL_TIM_PWM_Start(&htimx, TIM_CHANNEL_y)
HAL_TIM_PWM_Stop(&htimx, TIM_CHANNEL_y);
set pins for Tx and Rx (already set by default). Baud rate = 115200 b/s
HAL_UART_Receive(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_UART_Transmit(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
Note: data is a string pointer, size the length of the string
DMA:
- add Tx DMA entry on DMA settings
- enable global interrupt in NVIC settings
- enable normal mode and check the memory flag. as default data width is set to bytes
- Transmit callback:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
- Receive callback:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
There are three main modes of operation (end of conversion):
- Polling mode: checks at every loop iteration whether the conversion finished.
while(HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_OK)
- Simple interrupt mode: the ADC provides an interrupt at the end of the conversion and reads directly the value from the peripheral
HAL_ADC_Start_IT(&hadc1)
- DMA mode with interrupt: the ADC provides an interrupt when the value read from the peripheral is written on memory and ready to be accessed. DMA settings > add > Mode: Circular. DMA continuous requests: disabled
HAL_ADC_Start_DMA(&hadc1, (uint16_t*) data, bufflen)
There are three modes of starting the conversion:
- software-based: external trigger conversion = regular conversion started by software + delay to pause the conversions + ADC start in the while loop
- timer-based: external trigger conversion = timer 2 trigger out event + timer base start (configure timer 2 for the frequency of acquisition and set internal clock source & Trigger Event Selection = Update Event) + ADC start (outside while loop)
- external trigger source (EXTI_11 or EXTI_15)
In the example the sampling time is set to 480 cycles.
In order to read the value of the ADC, with values from 0 to 4096 (2^12):
HAL_ADC_GetValue(&hadc1)
Interrupt callbacks for reading the converted value
- Interrupt at half of the values converted:
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
- Interrupt at full number of values converted:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
Pin connections and ADC channel:
- PA0: ADC1_IN0 for the light LDR sensor
- PA1: ADC1_IN1 for the potentiometer
Configuration of the ADC parameters:
- set the pin PA1 as ADC_IN1
- check that IN1 is flagged in the ADC settings
- conversion mode: can be set to regular or circular depending on how to read the values and how many channels to read from
- external trigger conversion: [software OR Timer 2 Trigger Out event] for selection of the start of conversion
- end of conversion selection = eof at the end of single conversions
If many values are read, then different channels need to be sampled (IN1, temperature sensor channel and Vref):
- ADC_Regular_ConversionMode > NumberOfConversions = #values (or of different sensors to be sampled)
- set the correct Channels in every "Rank" label (and 480 cycles)
- scan conversion mode = enabled
- end of conversion = at the end of single channel conversion
- dma continuous requests = disabled
- continuous conversion mode = disabled
half-duplex, only 2 wires for all the connected devices (SCL clock and SDA data) but it's slow (max 400kbps in fast mode). wires are open drain, so we have a pull up that brings them at Vdd if nobody sets nothing
Used for interfacing with the LDR temperature sensor and the accelerometer LIS2DE
Parameters settings:
- I2C pins: PB9->SDA, PB8->SCL
- enable I2C1 communication
- receive callback function: enable NVIC settings -> event interrupt flag
- DMA: enable RX DMA channel with default settings and normal mode
functions:
HAL_I2C_Master_Transmit(&hi2c1, accAddress, dataBuf, 1, 10);
// dataBuf = uint8 register where data is stored by the peripheralHAL_I2C_Master_Receive(&hi2c1, accAddress, accBuf, 2, 10);
// accBuf = buffer of uint8_t data receivedHAL_I2C_Master_Receive_DMA(&hi2c1, accAddress, accBuf, 2);
// accBuf = buffer of uint8_t data receivedvoid HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
// callback called when data reception is completed- // accAddress = address of peripheral to access
(only led matrix) full-duplex, short distance communication, higher speed (42 Mbps SPI1,SPI4, 21 Mbps SPI2,SPI3)
LEDMATRIX code: SET gpio pb6, then transmit single column complete, then RESET gpio pb6
Parameter settings:
- use prescaler = 4, CPOL = low, CPHA = 1Edge
- {dataValue, colValue} MSB top-left
- Pin PA5 = SPI1_SCK; Pin PA7 = SPI_MOSI; Pin PB6 = GPIO_Output.
- SPI Mode: Transmit only master
- timer: quick enough to see continuous light (update all the led matrix in less than 4ms -> frequency > 1250Hz)
- DMA: add DMA with TX mode and default settings and normal code
Code:
HAL_SPI_Transmit(SPI_HandleTypeDef*hspi, uint8_t * pData, uint16_t Size, uint32_t Timeout)
// transmission of string pDataHAL_SPI_Transmit_DMA(SPI_HandleTypeDef*hspi, uint8_t * pData, uint16_t Size)
// no timeout required
enable PC6 = TIM3_CH1, PC7 = TIM3_CH2
Parameter settings:
- TIM3 combined channels = Encoder Mode
- first channel 1 -> polarity = falling edge, input filter = 15
- second channel 2 -> polarity = rising edge, input filter = 15
__HAL_TIM_GET_COUNTER(&htim3)
// to get the absolute value of the encoder rotationHAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
// start encoder timers
Pins: PC8,9,10,11 GPIO OUTPUT (column driver), PC12,13,2,3 GPIO INPUT (row readout)
Row is set to ground (0 value) if a button in the row is pressed, otherwise, if no buttons are pressed, the row is set to 1 debounce: register more presses of the button to validate it
- columns in order = 8 - 9 - 10 - 11
- rows in order = 12 - 13 - 2 - 3
Keyboard mapping buttons to a character:
char map [16] = "FB73EA62D951C840";
// columns in the map: 10 9 8 11 //rows in the map: 3 2 13 12
Configuration:
- timer 3 at 2400 Hz used to send an interrupt, waiting for the baud period, in order to send each bit every 1 / 2400 s (approximately 4 ms). Timer3 configured as a timer interrupt with PSC=0, ARR=35000-1
- timer 2 PWM on channel 3 is used to make the IR led pulse at 38 KHz. PSC=0, ARR=2211-1. Transmission of bit 1 requires PWM_Stop, instead tranmitting bit 0 requires PWM_Start. Transmission lasts a baud period, until the next bit is transmitted.
- infrared receiver output = high normally, output = low when IR light is detected
- the string is transmitted one byte at a time, where each byte is composed of 8 bits, and each bit transmits at the baud rate
- transmission via IR happens on UART1 interface at 2400 bytes/s baud rate
- reception of character (1 byte = 8 bits) via IR happens with
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- enable global interrupt for UART1
- PB10 = IR Led attached to TIM2_CH3 PWM
- PA10 receiver USART1RX
- PA9 transmitter USART1TX
Project -> properties -> C/C++ build -> Settings -> MCU settings -> check printf_float
-
HW_01_MICROPHONE : When a loud sound is detected the green led is switched on, when another loud sound is detected is switched off.
-
HW_01_PWM_LED: When a timer expires its callback swithc on or off the green led.
-
HW_02_SONG_DELAY: When a loud sound is detected the song start playing, to change the note is used the delay function.
-
HW_02_SONG_INTERRUPT: When a loud sound is detected the song start playing, to change the note is used a timer interrupt.
-
HW_03_LCD: Prints to the LCD screen the group member names.
-
HW_03_UART_DMA: The names and the year of birth of all the group members are sent to a remote terminal using the UART communication.
-
HW_04_ADC_LCD: The value of the voltage is converted using the adc and then is printed on the lcd screen (both numerical value and drawbar).
-
HW_04_ADC_POLLING: Reads the voltage value using ADC and print the value in a remote terminal using the UART communication. The ADC works in polling mode, the program is started in the software (inside the while loop), is used the delay function to manage the time interleaving between two consecuitive print.
-
HW_04_ADC_UART: Reads the voltage value using ADC with polling mode and print the value in a remote terminal using the UART communication. The ADC works in simple interrupt mode (when it expires the ADC converts the data), the program is started by a timer interrupt.
-
HW_05_ADC_DMA_3VALUES: Are red the temperature, Vref and potentiometer values using the ADC and are sent to a remote terminal using the UART communication. The ADC is started in the software and work in simple interrupt configuration, using the DMA in circular mode.
-
HW_O5_ADC_LDR: The LDR sensor is used to obtain 2000 samples of lux intensity, is done the avreage (the samples are aquired together and not singularly because otherwhise in the meanwhile that the average is beign computed som of the samples can be overwritten producing an incorrect result). Then the average value of lux intensity is sent to a remote terminal using the UART communication.
-
HW_06_I2C_11BIT_TEMPERATURE: Is red the temperature value (using 11 bit of precision) using the I2C commmunication, then is sent to a remote terminal using the UART communication.
-
HW_07ACCELEROMETER_UART_DMA: Is red the accelerometer x,y and z values using the I2C communication, then they're sent to a remote terminal using the UART DMA communication.
-
HW_07ACCELEROMETER_UART_I2C_DMA: Is red the accelerometer x,y and z values using the I2C communication in DMA mode, then they're sent to a remote terminal using the UART DMA communication.
-
HW_08_LED_MATRIX_DMA: Alternates the letter and the number of the group in the led matrix. It's used the SPI DMA commmunication.
-
HW_09_ENCODER: Is retrieved the absolute value of the encoder and the difference of this value and the previous count is sent to a remote terminal using the UART communication.
-
HW_10_KEYBOARD: When a button of the keyboard is pressed is sent to a remote terminal the corresponding character.
-
HW_10_KEYBOARD_TIMERS: When a button of the keyboard is being pressed for a specific amount of time (in this case 2 seconds) the corresponding character is sent to a remote terminal, if the same button continue to be pressed without releasing it, its character must not be sent again to the terminal.
-
HW_11_IR: A string is form the IR transmitter to the IR receiver, then the receiver re-transmit it to a remote terminal using the UART communication.
-
HW_11_2_IR_KEYBOARD: When a button of the keyboard is pressed the corresponding character is sent from the IR receiver to the IR transmitter. When the character is received is shown in the LED matrix using the SPI communication.
- Scanning the LDR 1000 times and return the average. Stopping the conversion when pressed a corner keybutton of the keyboard
- Both ends of the infrared communication, transmitting the temperature of the I2C sensor (not as formatted strings) and printing it on the LCD
- Ine the LSD project when the microphone detetcts a sound the display stop to show all the names and keep showing only the last one
- In the project of the keyboard if you push a button in the corner it produces a sound (different for each corner),if you oush any other button sitch on a led (if no button are pressed nothing has to be done)
- In the project of the accelerometer every one second provide the average of 1000 acceleration values of the three axes
- In the project of the led-matrix let alternate the two letters when the micorphone detects a sound and keep it working for 10 seconds