ECE3730J RC2_Input_Capture

Input Compare Module

IC is a peripheral that can monitor the input signal change (pos/neg edge) independent of the processor (Core).

![[Pasted image 20240617150723.png]]
You can consider IC as a timer value recorder. It will record the timer value each time the capture condition is met.

For detailed configuration, please refer to Reference Manual.pdf on canvas, page 349-359, 382-385.

Some useful documentation on the configuration register:
![[Pasted image 20240617155913.png]]
![[Pasted image 20240617155926.png]]
![[Pasted image 20240617155935.png]]

ECE3730J RC2

![](Pasted image 20240616202750.png)
Basically, we are using MCU to communicate with the LCD controller (HD44780).

Datasheet for HD44780: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

LCD Controller Pin

  1. VSS (Pin 1): Ground (GND).
  2. VDD (Pin 2): Power supply (usually +5V).
    Note: If you use J-link debugger to power the board, the output voltage at +5V pin will not be 5V, maybe around 2.8V, so remember to use the 5V power supply wire to power the board.
  3. VO (Pin 3): Contrast adjustment pin. Usually connected to a potentiometer to adjust the contrast.
  4. RS (Pin 4): Register select pin. Low for instruction register, high for data register.
  5. RW (Pin 5): Read/Write pin. Low for write operation, high for read operation. Usually grounded (write mode).
  6. E (Pin 6): Enable pin. The LCD controller only captures (grabs) the data presented at its register lines(D0-D7) only when the E pin “transitions” from high to low.
  7. D0-D7 (Pins 7-14): Data bus pins. Used for communication with the microcontroller in either 4-bit (D4-D7) or 8-bit (D0-D7) mode.
  8. A (Pin 15): For the backlight. Typically connected to +5V.
  9. K (Pin 16): For the backlight. Typically grounded (GND).

Connection with STM32

![](Pasted image 20240616210515.png)

Some Useful Charts

From datasheet

  1. Four operation
    ![[Pasted image 20240616212637.png]]
    IR: instruction register
    DR: data register

In this Lab, we will mainly use the first and third operation

  1. Instruction
    ![[Pasted image 20240616212934.png]]
    ![[Pasted image 20240616213009.png]]

  2. DDRAM
    ![[Pasted image 20240616214538.png]]

  3. CGRAM
    ![[Pasted image 20240616215520.png]]

Application Example

Send Command to LCD Controller

Recall the operation:
![[Pasted image 20240616220104.png]]

  1. Set the pin of RS & R/W to low.
  2. Set E to high, preparing for the data transfer.
  3. Set D7-D0 to the desired instruction(8-bit).
  4. Set E to low

Sample code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void LCD_Write_Command(uchar Com) {
Delay_ms(10);
HAL_GPIO_WritePin(GPIOB, LCD_RS_Pin, GPIO_PIN_RESET); // LCD_RS = 0;
HAL_GPIO_WritePin(GPIOB, LCD_RW_Pin, GPIO_PIN_RESET); // LCD_RW = 0;
HAL_GPIO_WritePin(GPIOB, LCD_E_Pin, GPIO_PIN_SET); // LCD_E_Pin = 1;
Delay_ms(1); // wait for tpw;

LCD_PORT = Com;// put command on the bus

HAL_GPIO_WritePin(GPIOB, LCD_E_Pin, GPIO_PIN_RESET); // LCD_E_Pin =0;
Delay_ms(1); // wait for tpw;

}

Write Data To DDRAM

Recall the operation:
![[Pasted image 20240616222832.png]]

  1. Set the pin of RS to high and R/W to low.

  2. Set E to high, preparing for the data transfer.

  3. Set D7-D0 to the desired address.
    ![[Pasted image 20240616223239.png]]

  4. Set E to low

Sample code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void LCD_Write_Data(uchar dat) {
Delay_ms(1);

HAL_GPIO_WritePin(GPIOB, LCD_RS_Pin, GPIO_PIN_SET); // LCD_RS = 1;
HAL_GPIO_WritePin(GPIOB, LCD_RW_Pin, GPIO_PIN_RESET); // LCD_RW = 0;
HAL_GPIO_WritePin(GPIOB, LCD_E_Pin, GPIO_PIN_SET); // LCD_E_Pin = 1;
// Delay_ms(1);

LCD_PORT = dat; // put data on the bus

HAL_GPIO_WritePin(GPIOB, LCD_E_Pin, GPIO_PIN_RESET); // Set LCD_E = 0;

Delay_ms(1); // wait for tpw;
}

Init LCD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define LCD_2_LINE_4_BITS 0x28
#define LCD_2_LINE_8_BITS 0x38
#define LCD_DSP_CSR 0x0c
#define LCD_CLR_DSP 0x01
#define LCD_CSR_INC 0x06

void LCD_init(void)
{
LCD_Write_Command(LCD_2_LINE_8_BITS); // function set -8 bit interface
Delay_ms(5);
LCD_Write_Command(LCD_2_LINE_8_BITS);

LCD_Write_Command(LCD_CLR_DSP); // clear display
Delay_us(100);
LCD_Write_Command(LCD_CSR_INC); // Set entry mode: increment
Delay_us(100);
LCD_Write_Command(LCD_DSP_CSR); // open display, close cursor
}

Display Charactor

First we need to set the cursor position

The cursor position is basically the DDRAM address that you want to write data in, which is corresponding to the display location on LCD screen.

1
2
3
4
5
6
7
8
9
void LCD_Set_Position(uchar x, uchar y) {
if (y == 0) // first line
{
LCD_Write_Command(0x80 + x);
} else if (y == 1) // second line
{
LCD_Write_Command(0xc0 + x);
}
}

If we want to display a character at first line, first column:

1
LCD_Set_Position(0,0);

Then, we need to write data into DDRAM[addr] to tell the LCD which character you want to display, for example “J”.

1
LCD_Write_Data("J"); // send the ascii code

Putting them all together:

1
2
3
4
5
void LCD_Display_Char(uchar Char, uchar x, uchar y)
{
LCD_Set_Position(x, y);
LCD_Write_Data(Char);
}

Display String

The cursor will shift right (because we set increment entry mode) after each write_data operation, so displaying a string is quite simple.

1
2
3
4
5
void LCD_Display_Char(uchar Char, uchar x, uchar y) // 显示字符ASCII码
{
LCD_Set_Position(x, y);
LCD_Write_Data(Char);
}

Demo

ECE3730J RC2_Output_Compare

Output Compare Module

OC is a peripheral that can generate precise output signal independent of the processor (Core).

![[Pasted image 20240617160331.png]]

Single Compare

Drive high, drive low, toggle
![[Pasted image 20240617154200.png]]

![[Pasted image 20240617154213.png]]
![[Pasted image 20240617154922.png]]

Dual Compare

Single pulse, continuous.
![[Pasted image 20240617154942.png]]
![[Pasted image 20240617154951.png]]

PWM

![[Pasted image 20240617155524.png]]

STM32 Development on Linux

System used: Archlinux

Pre-requirements

  • c language server (for completion, diagnostics), e.g. clangd
  • A code editor that use language server, e.g. vscode, vim/neovim

STM32CubeMX

STM32CubeMX is mainly responsible for generating the project with your configuration.

For Distro like Ubuntu/Debain, you can go to the ST official site
Or you can install the software through distro repository

1
yay -S stm32cubemx

For Arch, you need to modify the AUR repository (I mean, maybe the maintainer doesn’t do a good job).
The URL for the repository:https://aur.archlinux.org/packages/stm32cubemx

First clone the repository

1
git clone https://aur.archlinux.org/stm32cubemx.git

Modify the required jdk version in file stm32cubemx.sh
from exec archlinux-java-run --min 17 -- -jar /opt/stm32cubemx/STM32CubeMX "$@" to exec archlinux-java-run --min 17 --max 20 -- -jar /opt/stm32cubemx/STM32CubeMX "$@"

Then build and install the STM32CubeMX

1
makepkg --noconfirm --skipinteg -si

Since STM32CubeMX is not compatible with jdk22 (which is the default jdk that arch is currently using), you need to install jdk17 through yay -S jdk17-openjdk

Then you can start STM32CubeMX by running stm32cubemx, and hopefully, everything is fine.

Compiler

Use arm-none-eabi-gcc

1
2
yay -S arm-none-eabi-gcc
yay -S arm-none-eabi-newlib

Debugger

Use OpenOCD to burn and debug STM32 through STLink v2 (the blue USB device provided by us).

1
yay -S openocd

Setup Your STM32 Project

Open your STM32CubeMX, follow the instruction of Lab1.pdf to configure your project.

NOTE: In Project Manage -> Project -> Project Settings -> Toolchain / IDE, use Makefile/CMake.

Generate the code and go to the project directory (with Makefile/CMakeLists.txt in the directory).

Then you need to generate the compile_commands.json for clangd to recognize the project.

Makefile

1
bear -- make

CMake

1
cmake -S ./ -B ./build

Build Project

Makefile

1
make

Then target binary file is ./build/<Project Name>.bin

CMake

1
cmake --build ./build

Then target binary file is ./build/<Project Name>.elf

Load to STM32F103C8T6

Use OpenOCD to load the binary file to the board.

1
sudo openocd -f /usr/share/openocd/scripts/interface/stlink.cfg -f /usr/share/openocd/scripts/target/stm32f1x.cfg -c "program ./build/<Project Name>.bin reset exit 0x8000000"

Result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 1000 kHz
Info : STLINK V2J37S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.222587
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
Info : Listening on port 3333 for gdb connections
[stm32f1x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000dc8 msp: 0x20005000
** Programming Started **
Info : device id = 0x20036410
Info : flash size = 64 KiB
** Programming Finished **
** Resetting Target **
shutdown command invoked

NOTE: In different Distro, the cfg file for OpenOCD may locate in different directories. You need to find it by yourselves.

By the way, if you use CMake

Note: When uploading binary file to STM32, it’s recommended to use .bin file instead of .elf file.
Please use the following script to convert the .elf to .bin and upload.

1
2
3
4
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
cmake --build ./build
arm-none-eabi-objcopy -O binary -S ./build/*.elf ./build/target.bin
sudo openocd -f /usr/share/openocd/scripts/interface/stlink.cfg -f /usr/share/openocd/scripts/target/stm32f1x.cfg -c "program ./build/target.bin reset exit 0x8000000"

Debug

You have three possible choices. I recommend using Ozone.

reference:
https://rohanrhu.github.io/gdb-frontend/tutorials/embedded-debugging/

reference:
https://blog.csdn.net/qq_41757528/article/details/127741620

Segger Ozone!!!

reference:
https://blog.csdn.net/weixin_41572450/article/details/124710818

Maybe the best debug tool for stm32

To use segger ozone, you need a different linker called jlink (originally we use st-link v2). You need to buy this linker first (maybe on Taobao or Amazon).

Install Ozone through:

1
yay -S ozone

Setup of ozone project:

  • Start Ozone
  • Choose Device
    • Device: STM32F103C8
    • Register Set: Cortex-M3
    • Peripherials (optional): /opt/SEGGER/Ozone/Config/Peripherals/STM32F103xx.svd
  • Connection Settings
    • Target Interface: SWD
    • Target Interface Speed: 4MHz
    • Host Interface: USB
  • Program File: select the binary file you have built (.elf is recommended).

Debug:

set some breakpoints and watch some variables of your interest.
Press the green “power” icon on the upper left corner to start (upload the program and start the debugging process)
Press the blue “play” icon besides “power” to continue.

basic

Embeded System

Microprocessor

peripheral chips are needed to construct a product

Microcontroller

processor an peripheral functions implemented on a VLSI chip

Processing speed much slower and energy consuming is much lower