Components
This page describes the components used in the project.
- M95080-RMN6TP EEPROM
- PEC12R rotary Encoder
- 3X4 Matrix Keypad
- ST7565 LCD
- Tower Pro SG90 servo motor
- SHT40 temperature and humidity sensor
EEPROM
We are using the M95080-RMN6TP SPI EEPROM: http://www.st.com/resource/en/datasheet/m95080-r.pdf
The device exposes SPI pins (MISO, MOSI, SCK) plus EEPROM chip‑select (CS), HOLD, and write‑protect (WP) control pins.
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| SDI (MOSI) | PB15 (MOSI) | PTE2 |
| SDO (MISO) | PB14 (MISO) | PTE1 |
| SCK | PB13 | PTE0 |
| CS | PC13 | PTA13 |
| HOLD | PE6 | PTA11 |
| Write Protect | PE4 | PTE6 |
Here is an example algorithm for reading and writing to the EEPROM:
PROCEDURE EEPROM_WriteEnable()
SET command = 0x06 (WREN command)
PULL CS line LOW
SEND command over SPI
PULL CS line HIGH
END PROCEDURE
PROCEDURE EEPROM_WriteByte(address, data_byte)
IF address > 0x3FF THEN
RETURN (address out of range)
END IF
CREATE command_array with 3 elements:
command_array[0] = 0x02 (WRITE instruction)
command_array[1] = upper 3 bits of address (A10-A8)
command_array[2] = lower 8 bits of address (A7-A0)
CALL EEPROM_WriteEnable() to enable writing
PULL CS line LOW
SEND command_array (3 bytes) over SPI
SEND data_byte over SPI
PULL CS line HIGH
CALL EEPROM_WaitWriteComplete() to wait for completion
END PROCEDURE
PROCEDURE EEPROM_ReadByte(address) RETURNS byte
IF address > 0x3FF THEN
RETURN 0xFF (address out of range)
END IF
CREATE command_array with 3 elements:
command_array[0] = 0x03 (READ instruction)
command_array[1] = upper 3 bits of address (A10-A8)
command_array[2] = lower 8 bits of address (A7-A0)
INITIALIZE data_byte = 0
PULL CS line LOW
SEND command_array (3 bytes) over SPI
READ data_byte from SPI
PULL CS line HIGH
RETURN data_byte
END PROCEDURE
- Explanation:
EEPROM_WriteEnablesends the WREN (0x06) command so that the next write operation is accepted by the EEPROM.EEPROM_WriteBytebuilds a 3‑byte command frame: the WRITE opcode (0x02) followed by the 11‑bit address split into high bits A10..A8 and low bits A7..A0. It then sends this frame and the data byte over SPI, and finally waits until the internal write cycle finishes.EEPROM_ReadBytebuilds a similar 3‑byte frame with the READ opcode (0x03), sends it, and then reads back one data byte from the EEPROM.
The helper functions eeprom_spi_write, eeprom_spi_read,
EEPROM_CS_LOW, EEPROM_CS_HIGH, and EEPROM_WaitWriteComplete are
thin wrappers around the actual SPI and GPIO operations (for example,
HAL or another driver), so the high‑level EEPROM logic remains clear.
Encoder
We are using a PEC12R rotary contacting encoder.
Documentation: https://componentsearchengine.com/Datasheets/5/PEC12R-4220F-S0024.pdf
The encoder is already mounted on the D3S board and can be accessed from the STM32 board.
The rotation is detected using two signals, A and B. When A is pulled low (active), it indicates movement; if B then goes low the rotation is clockwise, and if B stays high the rotation is counter‑clockwise.
There is also an integrated push button. All three pins can be used as normal GPIO inputs.
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| ENC_A | PE10 | PTB13 |
| ENC_B | PE11 | PTA6 |
| ENC_BTN | PE12 | PTE7 |
Keypad
We are using a 3×4 matrix keypad. The datasheet is available here.
The keypad has 3 columns and 4 rows. Configure the column pins as inputs and the row pins as outputs.
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| COL1 | PD9 | PTB3 |
| COL2 | PD10 | PTC14 |
| COL3 | PD11 | PTC15 |
| ROW1 | PE15 | PTC9 |
| ROW2 | PB11 | PTB0 |
| ROW3 | PB12 | PTB1 |
| ROW4 | PD8 | PTB2 |
Example C implementation for scanning the keypad:
DECLARE keypad_map as array:
['1', '2', '3',
'4', '5', '6',
'7', '8', '9',
'*', '0', '#']
FUNCTION read_keypad() RETURNS character
FOR each row from 0 to ROWS-1:
// Activate current row, deactivate others
FOR each setup_row from 0 to ROWS-1:
IF setup_row equals current row THEN
SET row pin to ACTIVE_LEVEL
ELSE
SET row pin to INACTIVE_LEVEL
END IF
END FOR
// Check each column for button press
FOR each col from 0 to COLS-1:
IF column pin reads LOW (button pressed) THEN
CALCULATE key_index = row * COLS + col
RETURN keypad_map[key_index]
END IF
END FOR
END FOR
RETURN null character (no key pressed)
END FUNCTION
LCD
We are using an ST7565 graphical LCD: https://www.hpinfotech.ro/ST7565.pdf
The LCD is connected to the STM32 via the SPI2 interface.
The LCD uses SDI and SCK for SPI, plus DC (data/command select), CS (chip select), and RST (reset) control inputs.
There is a dedicated connector on the D3S board for the LCD module, so the STM32 can access it directly.
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| SDI | PB15 (MOSI) | PTE2 |
| SCK | PB13 | PTE0 |
| DC | PE2 | PTC5 |
| CS | PE5 | TPA12 |
| RST | PB7 | PTA10 |
Example initialization code:
PROCEDURE ST7565_WriteCommand(command_byte)
SET DC pin to LOW (command mode)
SET CS pin to LOW (select device)
SEND command_byte over SPI
SET CS pin to HIGH (deselect device)
END PROCEDURE
PROCEDURE ST7565_WriteData(data_byte)
SET DC pin to HIGH (data mode)
SET CS pin to LOW (select device)
SEND data_byte over SPI
SET CS pin to HIGH (deselect device)
END PROCEDURE
PROCEDURE ST7565_Init()
CALL ST7565_Reset() to toggle RST pin
WAIT 50 milliseconds after reset
// Send initialization commands
SEND command 0xAE (Display OFF)
SEND command 0xA2 (Set bias to 1/9)
SEND command 0xA0 (ADC normal direction)
SEND command 0xC8 (COM output reverse direction)
SEND command 0x22 (Set resistor ratio)
SEND command 0x2F (Power control: all circuits ON)
SEND command 0x40 (Set start line to 0)
SEND command 0xAF (Display ON)
// Optional contrast setting
SEND command (0x20 OR 0x06) to set resistor ratio for contrast
END PROCEDURE
Servo Motor
We are using a Tower Pro SG90 servo motor.
The servo is controlled using a PWM signal (e.g., from timer TIM1 on the STM32).
Documentation: http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf
On the D3S board the control pin is labeled orange, matching the
orange wire of the servo cable.
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| PWM | PE9 | PTB12 |
Temperature and Humidity Sensor
We are using an SHT40 temperature and humidity sensor. It is already mounted on the D3S board and can be accessed from the STM32 board.
For the sensor datasheet, see: https://www.laskakit.cz/user/related_files/sht4x.pdf
The sensor uses the I²C bus for communication (see the I²C specification here: https://www.nxp.com/docs/en/user-guide/UM10204.pdf).
| Pin | STM32 Pin | D3S Pin |
|---|---|---|
| SCL | PA8 | PTA3 |
| SDA | PC9 | PTA2 |
Note: the sensor I²C address is 0x45.
Example code on STM32:
PROCEDURE read_temperature_and_humidity(i2c_handle, temperature_pointer, humidity_pointer)
DECLARE command_byte = 0xFD
DECLARE sensor_address = 0x45
// Send measurement command
CALL i2c_write(i2c_handle, sensor_address shifted left by 1, command_byte, 1 byte, 100ms timeout)
WAIT 30 milliseconds for measurement completion
// Read measurement data (6 bytes total)
DECLARE receive_buffer[6]
CALL i2c_read(i2c_handle, sensor_address shifted left by 1, receive_buffer, 6 bytes, 100ms timeout)
// Parse temperature data
CALCULATE temperature_raw = receive_buffer[0] * 256 + receive_buffer[1]
SET temperature_checksum = receive_buffer[2]
// Parse humidity data
CALCULATE humidity_raw = receive_buffer[3] * 256 + receive_buffer[4]
SET humidity_checksum = receive_buffer[5]
// Handle checksum error case
IF temperature_checksum equals 0 AND humidity_checksum equals 0 THEN
SET humidity_pointer value to 0.0
END IF
// Convert raw values to actual temperature and humidity
CALCULATE temperature_celsius = -45 + (175 * (temperature_raw / 65535.0))
CALCULATE humidity_percent = -6 + (125 * (humidity_raw / 65535.0))
// Clamp humidity to valid range [0, 100]
IF humidity_percent > 100.0 THEN
SET humidity_percent = 100.0
END IF
IF humidity_percent < 0.0 THEN
SET humidity_percent = 0.0
END IF
// Store results
SET temperature_pointer value to temperature_celsius
SET humidity_pointer value to humidity_percent
END PROCEDURE
JOYSTICK
More details to be added.