Home | Projects | Notes > MCU Peripheral Drivers > Board Support Package (BSP) (rtc_ds1307.h/.c
, lcd_hd44780u.h/.c
)
rtc_ds1307.h/.c
, lcd_hd44780u.h/.c
)
rtc_ds1307.h
Contains device (RTC) related information
I2C address (For this project, slave address)
Register addresses (Registers from which the date and time information can be extracted)
Data structure to handle information
Prototypes of the functions that are to be exposed to user applications
Application configurable items
xxxxxxxxxx
811/*******************************************************************************
2 * File : rtc_ds1307.h
3 * Brief : APIs for the DS1307 RTC module
4 * Author : Kyungjae Lee
5 * Date : Jun 25, 2023
6 *
7 * Note : This code includes only the features that are necessary for my
8 * personal projects.
9 ******************************************************************************/
10
11
12
13
14
15
16/* Application configurable items */
17
18
19
20
21/* Doesn't support fast mode */
22/* Using internal pull-up R */
23
24/* Register addresses */
25
26
27
28
29
30
31
32
33/* DS1307 I2C address */
34/* 1101000(2) */
35
36/* Time formats */
37
38
39
40
41/* Days */
42
43
44
45
46
47
48
49
50/* RTC date configuration structure */
51typedef struct
52{
53 uint8_t date;
54 uint8_t month;
55 uint8_t year;
56 uint8_t day;
57} RTC_Date_TypeDef;
58
59/* RTC time configuration structure */
60typedef struct
61{
62 uint8_t seconds;
63 uint8_t minutes;
64 uint8_t hours;
65 uint8_t timeFormat;
66} RTC_Time_TypeDef;
67
68
69/*******************************************************************************
70 * APIs supported by the DS1307 RTC module
71 * (See the function definitions for more information)
72 ******************************************************************************/
73
74uint8_t DS1307_Init(void);
75void DS1307_SetCurrentTime(RTC_Time_TypeDef *);
76void DS1307_GetCurrentTime(RTC_Time_TypeDef *);
77void DS1307_SetCurrentDate(RTC_Date_TypeDef *);
78void DS1307_GetCurrentDate(RTC_Date_TypeDef *);
79
80
81/* RTC_DS1307_H */
rtc_ds1307.c
xxxxxxxxxx
3181/*******************************************************************************
2 * File : rtc_ds1307.c
3 * Brief : Implementation of APIs for the DS1307 RTC module
4 * Author : Kyungjae Lee
5 * Date : Jun 25, 2023
6 *
7 * Note : This code includes only the features that are necessary for my
8 * personal projects.
9 ******************************************************************************/
10
11
12/* memset() */
13
14
15/* Private function prototypes */
16static void DS1307_I2CPinConfig(void);
17static void DS1307_I2CConfig(void);
18static void DS1307_Write(uint8_t value, uint8_t regAddr);
19static uint8_t DS1307_Read(uint8_t regAddr);
20static uint8_t BcdToBinary(uint8_t bcd);
21static uint8_t BinaryToBcd(uint8_t binary);
22
23/* Global variables */
24I2C_Handle_TypeDef gDS1307I2CHandle;
25
26/**
27 * DS1307_Init()
28 * Desc. : Initializes DS1307 RTC module
29 * Param. : None
30 * Return : 0 if setting DS1307_SEC CH bit to 0 was successful (init success),
31 * 1 otherwise (init fail)
32 * Note : N/A
33 */
34uint8_t DS1307_Init(void)
35{
36 /* 1. Initialize the I2C pins */
37 DS1307_I2CPinConfig();
38
39 /* 2. Initialize the I2C peripheral */
40 DS1307_I2CConfig();
41
42 /* 3. Enable the I2C peripheral */
43 I2C_PeriControl(DS1307_I2C, ENABLE);
44
45 /* 4. Set Clock Halt (CH) bit to 0 to initiate time keeping
46 * Note: At power on, the time keeping will not function until the CH bit
47 * becomes 0. So, to initiate the time keeping functionality the
48 * master needs to write 0 to the slave's CH bit.
49 * For data write logic, see the "I2C Data Bus" section of DS1307
50 * reference manual.
51 */
52 DS1307_Write(0x0, DS1307_SEC);
53
54 /* 5. Read back Clock Halt (CH) bit
55 * Note: For data read logic, see the "I2C Data Bus" section of DS1307
56 * reference manual.
57 */
58 uint8_t clockState = DS1307_Read(DS1307_SEC);
59
60 return ((clockState >> 7) & 0x1);
61}
62
63/**
64 * DS1307_SetCurrentTime()
65 * Desc. : Sets the DS1307 Seconds, Minutes, Hours registers according to
66 * the values configured in @rtcTime
67 * Param. : @rtcTime - pointer to the RTC Time structure which contains the
68 * values configured by the user
69 * Return : None
70 * Note : N/A
71 */
72void DS1307_SetCurrentTime(RTC_Time_TypeDef *rtcTime)
73{
74 uint8_t secs, hrs;
75
76 /* Set seconds -----------------------------------------------------------*/
77
78 secs = BinaryToBcd(rtcTime->seconds);
79
80 /* Make sure to keep the CH bit (bit[7]) of the Seconds register */
81 secs &= ~(0x1 << 7);
82
83 DS1307_Write(secs, DS1307_SEC);
84
85 /* Set minutes -----------------------------------------------------------*/
86
87 DS1307_Write(BinaryToBcd(rtcTime->minutes), DS1307_MIN);
88
89 /* Set hours -------------------------------------------------------------*/
90
91 hrs = BinaryToBcd(rtcTime->hours);
92
93 if (rtcTime->timeFormat == TIME_FORMAT_24HRS)
94 {
95 /* To use 24HRS time format, clear bit[6] of the Hours register */
96 hrs &= ~(0x1 << 6);
97 }
98 else
99 {
100 /* To use 12HRS time format, set bit[6] of the Hours register */
101 hrs |= (0x1 << 6);
102
103 /* If PM, set bit[5] of the Hours register, if AM, clear it */
104 hrs = (rtcTime->timeFormat == TIME_FORMAT_12HRS_PM) ? hrs | (0x1 << 5) : hrs & ~(0x1 << 5);
105 }
106
107 DS1307_Write(hrs, DS1307_HR);
108} /* End of DS1307_SetCurrentTime */
109
110/**
111 * DS1307_GetCurrentTime()
112 * Desc. : Gets the current time information and stores it into @rtcTime
113 * Param. : @rtcTime - RTC_Time structure to store the current time info
114 * Return : None
115 * Note : N/A
116 */
117void DS1307_GetCurrentTime(RTC_Time_TypeDef *rtcTime)
118{
119 uint8_t secs, hrs;
120
121 /* Get seconds -----------------------------------------------------------*/
122
123 secs = DS1307_Read(DS1307_SEC);
124 secs &= ~(0x1 << 7); /* Exclude unnecessary bits */
125 rtcTime->seconds = BcdToBinary(secs);
126
127 /* Get minutes -----------------------------------------------------------*/
128
129 rtcTime->minutes = BcdToBinary(DS1307_Read(DS1307_MIN));
130
131 /* Get hours -------------------------------------------------------------*/
132
133 hrs = DS1307_Read(DS1307_HR);
134
135 if (hrs & (0x1 << 6))
136 {
137 /* 12HRS format */
138 rtcTime->timeFormat = !((hrs & (0x1 << 5)) == 0);
139 hrs &= ~(0x3 << 5); /* Clear bit[6] and bit[5] */
140 }
141 else
142 {
143 /* 24HRS format */
144 rtcTime->timeFormat = TIME_FORMAT_24HRS;
145 }
146
147 rtcTime->hours = BcdToBinary(hrs);
148} /* End of DS1307_GetCurrentTime */
149
150/**
151 * DS1307_SetCurrentDate()
152 * Desc. : Sets the current date information into @rtcDate
153 * Param. : @rtcDate - RTC_Date structure which contains the current date info
154 * Return : None
155 * Note : N/A
156 */
157void DS1307_SetCurrentDate(RTC_Date_TypeDef *rtcDate)
158{
159 DS1307_Write(BinaryToBcd(rtcDate->date), DS1307_DATE);
160 DS1307_Write(BinaryToBcd(rtcDate->month), DS1307_MONTH);
161 DS1307_Write(BinaryToBcd(rtcDate->year), DS1307_YEAR);
162 DS1307_Write(BinaryToBcd(rtcDate->day), DS1307_DAY);
163} /* End of DS1307_SetCurrentDate */
164
165/**
166 * DS1307_GetCurrentDate()
167 * Desc. : Gets the current date information and stores it into @rtcDate
168 * Param. : @rtcDate - RTC_Date structure to store the current date info
169 * Return : None
170 * Note : N/A
171 */
172void DS1307_GetCurrentDate(RTC_Date_TypeDef *rtcDate)
173{
174 rtcDate->day = BcdToBinary(DS1307_Read(DS1307_DAY));
175 rtcDate->date = BcdToBinary(DS1307_Read(DS1307_DATE));
176 rtcDate->month = BcdToBinary(DS1307_Read(DS1307_MONTH));
177 rtcDate->year = BcdToBinary(DS1307_Read(DS1307_YEAR));
178} /* End of DS1307_GetCurrentDate */
179
180
181/*******************************************************************************
182 * Private functions
183 ******************************************************************************/
184
185/**
186 * DS1307_I2CPinConfig()
187 * Desc. : Configures the GPIO pins to be used for I2C communication
188 * Param. : None
189 * Return : None
190 * Note : N/A
191 */
192static void DS1307_I2CPinConfig(void)
193{
194 GPIO_Handle_TypeDef i2cSda, i2cScl;
195
196 /* Zero-out all the fields in the structures (Very important! i2cSda, i2cScl
197 * are local variables whose members may be filled with garbage values before
198 * initialization. These garbage values may set (corrupt) the bit fields that
199 * you did not touch assuming that they will be 0 by default. Do NOT make this
200 * mistake!
201 */
202 memset(&i2cSda, 0, sizeof(i2cSda));
203 memset(&i2cScl, 0, sizeof(i2cScl));
204
205 /*
206 * I2C1_SCL: PB6
207 * I2C1_SDA: PB7
208 */
209
210 i2cSda.pGPIOx = DS1307_I2C_GPIO_PORT;
211 i2cSda.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;
212 i2cSda.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;
213 i2cSda.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SDA;
214 i2cSda.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;
215 i2cSda.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;
216 i2cSda.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
217
218 GPIO_Init(&i2cSda);
219
220 i2cScl.pGPIOx = DS1307_I2C_GPIO_PORT;
221 i2cScl.GPIO_PinConfig.GPIO_PinAltFcnMode = 4;
222 i2cScl.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_ALTFCN;
223 i2cScl.GPIO_PinConfig.GPIO_PinNumber = DS1307_I2C_PIN_SCL;
224 i2cScl.GPIO_PinConfig.GPIO_PinOutType= GPIO_PIN_OUT_TYPE_OD;
225 i2cScl.GPIO_PinConfig.GPIO_PinPuPdControl = DS1307_I2C_PUPD;
226 i2cScl.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
227
228 GPIO_Init(&i2cScl);
229} /* End of DS1307_I2CPinConfig */
230
231/**
232 * DS1307_I2CConfig()
233 * Desc. : Configures and initializes DS1307 I2C peripheral
234 * Param. : None
235 * Return : None
236 * Note : N/A
237 */
238static void DS1307_I2CConfig(void)
239{
240 gDS1307I2CHandle.pI2Cx = DS1307_I2C;
241 gDS1307I2CHandle.I2C_Config.I2C_ACKEnable = I2C_ACK_ENABLE;
242 gDS1307I2CHandle.I2C_Config.I2C_SCLSpeed = DS1307_I2C_SPEED;
243 I2C_Init(&gDS1307I2CHandle);
244} /* End of DS1307_I2CConfig */
245
246/**
247 * DS1307_Write()
248 * Desc. : Writes @value to @regAddr
249 * Param. : @value - value to write to @regAddr
250 * @regAddr - DS1307 register address to write @value to
251 * Return : None
252 * Note : N/A
253 */
254static void DS1307_Write(uint8_t value, uint8_t regAddr)
255{
256 uint8_t tx[2];
257 tx[0] = regAddr;
258 tx[1] = value;
259 I2C_MasterTxBlocking(&gDS1307I2CHandle, tx, 2, DS1307_I2C_ADDR, 0);
260
261} /* End of DS1307_Write */
262
263/**
264 * DS1307_Read()
265 * Desc. : Writes @value to @regAddr
266 * Param. : @regAddr - DS1307 register address to read from
267 * Return : 1-byte data received from the slave (DS1307 RTC module)
268 * Note : N/A
269 */
270static uint8_t DS1307_Read(uint8_t regAddr)
271{
272 uint8_t rxData;
273 I2C_MasterTxBlocking(&gDS1307I2CHandle, ®Addr, 1, DS1307_I2C_ADDR, 0);
274 I2C_MasterRxBlocking(&gDS1307I2CHandle, &rxData, 1, DS1307_I2C_ADDR, 0);
275
276 return rxData;
277} /* End of DS1307_Read */
278
279/**
280 * BcdToBinary()
281 * Desc. : Converts the passed Binary-Coded Decimal (BCD) value to binary
282 * Param. : @bcd - binary-coded decimal value to be converted into binary
283 * Return : @bcd in binary representation
284 * Note : N/A
285 */
286static uint8_t BcdToBinary(uint8_t bcd)
287{
288 uint8_t tens, ones;
289
290 tens = (uint8_t)((bcd >> 4) * 10);
291 ones = bcd & (uint8_t)0xF;
292
293 return tens + ones;
294} /* End of BcdToBinary */
295
296/**
297 * BinaryToBcd()
298 * Desc. : Converts the passed binary value to Binary-Coded Decimal (BCD)
299 * Param. : @binary - binary value to be converted into binary-coded decimal
300 * Return : @binary in binary-coded decimal representation
301 * Note : N/A
302 */
303uint8_t BinaryToBcd(uint8_t binary)
304{
305 uint8_t tens, ones;
306 uint8_t bcd;
307
308 bcd = binary;
309
310 if (binary >= 10)
311 {
312 tens = binary / 10;
313 ones = binary % 10;
314 bcd = (tens << 4) | ones;
315 }
316
317 return bcd;
318} /* End of BinaryToBcd */
lcd_hd44780u.h
xxxxxxxxxx
3031/*******************************************************************************
2 * File : lcd_hd44780u.c
3 * Brief : Implementation of APIs for the HD44780U 16x2 Character LCD module
4 * (4-bit interface; only DB4-7 pins of the LCD module will be used)
5 * Author : Kyungjae Lee
6 * Date : Jun 27, 2023
7 *
8 * Note : This code includes only the features that are necessary for my
9 * personal projects.
10 ******************************************************************************/
11
12
13
14
15/* Function prototypes */
16static void Write4Bits(uint8_t nibble);
17static void LCD_Enable(void);
18static void DelayMs(uint32_t delayInMs);
19static void DelayUs(uint32_t delayInUs);
20
21/**
22 * LCD_Init()
23 * Desc. : Initializes GPIO pins to be used for LCD connections
24 * Param. : None
25 * Return : None
26 * Note : N/A
27 */
28void LCD_Init(void)
29{
30 GPIO_Handle_TypeDef gpioPin;
31
32 /* 1. Configure the GPIO pins to be used for LCD connections -------------*/
33
34 /* Configure the GPIO pin to be connected to LCD RS pin */
35 gpioPin.pGPIOx = LCD_GPIO_PORT;
36 gpioPin.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_OUT;
37 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RS;
38 gpioPin.GPIO_PinConfig.GPIO_PinOutType = GPIO_PIN_OUT_TYPE_PP;
39 gpioPin.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_NO_PUPD;
40 gpioPin.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
41 GPIO_Init(&gpioPin);
42
43 /* Configure the GPIO pin to be connected to LCD RW pin */
44 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RW;
45 GPIO_Init(&gpioPin);
46
47 /* Configure the GPIO pin to be connected to LCD EN pin */
48 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_EN;
49 GPIO_Init(&gpioPin);
50
51 /* Configure the GPIO pin to be connected to LCD D4 pin */
52 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D4;
53 GPIO_Init(&gpioPin);
54
55 /* Configure the GPIO pin to be connected to LCD D5 pin */
56 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D5;
57 GPIO_Init(&gpioPin);
58
59 /* Configure the GPIO pin to be connected to LCD D6 pin */
60 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D6;
61 GPIO_Init(&gpioPin);
62
63 /* Configure the GPIO pin to be connected to LCD D7 pin */
64 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D7;
65 GPIO_Init(&gpioPin);
66
67 /* Set the configured GPIO pins' output values to 0 */
68 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
69 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
70 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);
71 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, RESET);
72 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, RESET);
73 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, RESET);
74 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, RESET);
75
76 /* 2. Initialize LCD module ------------------------------------------------
77 * (See 'Figure 24. 4-Bit Interface' in the LCD reference manual)
78 */
79
80 /* Wait for more than 40 ms after Vcc rises to 2.7V */
81 DelayMs(40);
82
83 /* Set RS pin to 0 for LCD command */
84 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
85
86 /* Set RW pin to 0 for writing to LCD (If you are always writing to LCD, you
87 * can keep this pin connected to GND)
88 */
89 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
90
91 Write4Bits(0x3); /* 0 0 1 1 in D7 D6 D5 D4 order */
92
93 DelayMs(5);
94
95 Write4Bits(0x3);
96
97 DelayUs(150);
98
99 Write4Bits(0x3);
100 Write4Bits(0x2);
101
102 /* Now, ready to send the command */
103
104 /* Set to use 4 data lines, 2 lines, 5x8 char font size */
105 LCD_TxInstruction(LCD_INST_4DL_2N_5X8F);
106
107 /* Set display on, cursor on */
108 LCD_TxInstruction(LCD_INST_DON_CURON);
109
110 /* Clear display */
111 LCD_ClearDisplay();
112
113 /* Entry mode set */
114 LCD_TxInstruction(LCD_INST_INCADD);
115
116} /* End of LCD_Init */
117
118/**
119 * LCD_TxInstruction()
120 * Desc. : Sends passed instruction (@instruction) to LCD
121 * Param. : @instruction - LCD instruction to send
122 * Return : None
123 * Note : N/A
124 */
125void LCD_TxInstruction(uint8_t instruction)
126{
127 /* 1. Set RS=0 for LCD command */
128 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
129
130 /* 2. Set RW=0 for write */
131 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
132
133 Write4Bits(instruction >> 4); /* Send the higher nibble */
134 Write4Bits(instruction & 0xF); /* Send the lower nibble */
135} /* End of LCD_TxInstruction */
136
137/**
138 * LCD_PrintChar()
139 * Desc. : Sends a character to be printed to the LCD
140 * Param. : @ch - character to print
141 * Return : None
142 * Note : This function assumes 4-bit parallel data transmission.
143 * First, the higher nibble of the data will be sent through the data
144 * lines D4, D5, d6, d7,
145 * then, the lower nibble of the data will be sent through the data
146 * lines D4, D5, d6, d7.
147 */
148void LCD_PrintChar(uint8_t ch)
149{
150 /* 1. Set RS=1 for LCD user data */
151 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, SET);
152
153 /* 2. Set RW=0 for write */
154 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
155
156 Write4Bits(ch >> 4); /* Send the higher nibble */
157 Write4Bits(ch & 0xF); /* Send the lower nibble */
158} /* End of LCD_TxChar */
159
160/**
161 * LCD_ClearDisplay()
162 * Desc. : Performs display clear routine
163 * Param. : None
164 * Return : None
165 * Note : After sending the clear display instruction, give it 2 ms as per
166 * the datasheet of LCD (See p.24 of LCD datasheet).
167 */
168void LCD_ClearDisplay(void)
169{
170 /* Clear display */
171 LCD_TxInstruction(LCD_INST_CLEAR_DISPLAY);
172
173 DelayMs(2); /* Wait 2 ms as per the datasheet */
174} /* End of LCD_ClearDisplay */
175
176/**
177 * LCD_ReturnHome()
178 * Desc. : Returns the cursor to the home position
179 * Param. : None
180 * Return : None
181 * Note : After sending the clear display instruction, give it 2 ms as per
182 * the datasheet of LCD (See p.24 of LCD datasheet).
183 */
184void LCD_ReturnHome(void)
185{
186 /* Return home */
187 LCD_TxInstruction(LCD_INST_RETURN_HOME);
188
189 DelayMs(2); /* Wait 2 ms as per the datasheet */
190} /* End of LCD_ReturnHome */
191
192/**
193 * LCD_PrintString()
194 * Desc. : Prints the passed string @msg to the LCD screen
195 * Param. : @msg - string to print
196 * Return : None
197 * Note : N/A
198 */
199void LCD_PrintString(char *msg)
200{
201 do
202 {
203 LCD_PrintChar((uint8_t)*msg++);
204 }
205 while (*msg != '\0');
206} /* End of LCD_PrintString */
207
208/**
209 * LCD_SetCursor()
210 * Desc. : Sets the cursor position (@row, @column)
211 * Param. : @row - the row in which the cursor should be placed
212 * @column - the column in which the cursor should be placed
213 * Return : None
214 * Note : Row number: 1 ~ 2
215 * Column number: 1 ~ 16 assuming a 2x16 character display
216 */
217void LCD_SetCursor(uint8_t row, uint8_t column)
218{
219 column--;
220
221 switch (row)
222 {
223 case 1:
224 /* Set cursor to 1st row address and add index */
225 LCD_TxInstruction((column |= 0x80));
226 break;
227 case 2:
228 /* Set cursor to 2nd row address and add index */
229 LCD_TxInstruction((column |= 0xC0));
230 break;
231 default:
232 break;
233 }
234} /* End of LCD_SetCursor */
235
236
237/*******************************************************************************
238 * Private functions
239 ******************************************************************************/
240
241/**
242 * DelayMs()
243 * Desc. : Spinlock delays for @delayInMs milliseconds
244 * Param. : @delayInMs - time to delay in milliseconds
245 * Returns : None
246 * Note : N/A
247 */
248static void DelayMs(uint32_t delayInMs)
249{
250 for (uint32_t i = 0; i < delayInMs * 1000; i++);
251} /* End of DelayMs */
252
253/**
254 * DelayUs()
255 * Desc. : Spinlock delays for @delayInUs microseconds
256 * Param. : @delayInUs - time to delay in microseconds
257 * Returns : None
258 * Note : N/A
259 */
260static void DelayUs(uint32_t delayInUs)
261{
262 for (uint32_t i = 0; i < delayInUs * 1; i++);
263} /* End of DelayMs */
264
265/**
266 * Write4Bits()
267 * Desc. : Writes 4 bits of data/command to D4, D5, D6, D7 lines
268 * (msb to D7, lsb to D4)
269 * Param. : @value -
270 * Return : None
271 * Note : N/A
272 */
273static void Write4Bits(uint8_t nibble)
274{
275 /* Write each bit of @nibble to D4-D7 lines */
276 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, (nibble >> 0) & 0x1);
277 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, (nibble >> 1) & 0x1);
278 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, (nibble >> 2) & 0x1);
279 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, (nibble >> 3) & 0x1);
280
281 /* After writing every nibble to the data lines, give the LCD time to latch
282 * that data inside the LCD
283 */
284 /* Make high-to-low transition on EN pin (See the timing diagram) */
285 LCD_Enable();
286
287} /* End of Write4Bits */
288
289/**
290 * LCD_Enable()
291 * Desc. : Makes high-to-low transition on the EN line
292 * Param. : None
293 * Return : None
294 * Note : For the instruction execution time, give any value that is greater
295 * than 32 micro-seconds.
296 */
297static void LCD_Enable(void)
298{
299 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, SET);
300 DelayUs(10);
301 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);
302 DelayUs(100);
303} /* End of LCD_Enable */
lcd_hd44780u.c
xxxxxxxxxx
3021/*******************************************************************************
2 * Filename : lcd_hd44780u.c
3 * Description : Implementation of APIs for 16x2 Character LCD module
4 * (4-bit interface; only DB4-DB7 pins of the LCD module will be
5 * used)
6 * Author : Kyungjae Lee
7 * History : Jun 27, 2023 - Created file
8 ******************************************************************************/
9
10
11
12
13/* Function prototypes */
14static void Write4Bits(uint8_t nibble);
15static void LCD_Enable(void);
16static void DelayMs(uint32_t delayInMs);
17static void DelayUs(uint32_t delayInUs);
18
19/**
20 * LCD_Init()
21 * Desc. : Initializes GPIO pins to be used for LCD connections
22 * Param. : None
23 * Return : None
24 * Note : N/A
25 */
26void LCD_Init(void)
27{
28 GPIO_Handle_TypeDef gpioPin;
29
30 /* 1. Configure the GPIO pins to be used for LCD connections -------------*/
31
32 /* Configure the GPIO pin to be connected to LCD RS pin */
33 gpioPin.pGPIOx = LCD_GPIO_PORT;
34 gpioPin.GPIO_PinConfig.GPIO_PinMode = GPIO_PIN_MODE_OUT;
35 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RS;
36 gpioPin.GPIO_PinConfig.GPIO_PinOutType = GPIO_PIN_OUT_TYPE_PP;
37 gpioPin.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_NO_PUPD;
38 gpioPin.GPIO_PinConfig.GPIO_PinSpeed = GPIO_PIN_OUT_SPEED_HIGH;
39 GPIO_Init(&gpioPin);
40
41 /* Configure the GPIO pin to be connected to LCD RW pin */
42 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_RW;
43 GPIO_Init(&gpioPin);
44
45 /* Configure the GPIO pin to be connected to LCD EN pin */
46 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_EN;
47 GPIO_Init(&gpioPin);
48
49 /* Configure the GPIO pin to be connected to LCD D4 pin */
50 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D4;
51 GPIO_Init(&gpioPin);
52
53 /* Configure the GPIO pin to be connected to LCD D5 pin */
54 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D5;
55 GPIO_Init(&gpioPin);
56
57 /* Configure the GPIO pin to be connected to LCD D6 pin */
58 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D6;
59 GPIO_Init(&gpioPin);
60
61 /* Configure the GPIO pin to be connected to LCD D7 pin */
62 gpioPin.GPIO_PinConfig.GPIO_PinNumber = LCD_PIN_D7;
63 GPIO_Init(&gpioPin);
64
65 /* Set the configured GPIO pins' output values to 0 */
66 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
67 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
68 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);
69 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, RESET);
70 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, RESET);
71 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, RESET);
72 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, RESET);
73
74 /* 2. Initialize LCD module ------------------------------------------------
75 * (See 'Figure 24. 4-Bit Interface' in the LCD reference manual)
76 */
77
78 /* Wait for more than 40 ms after Vcc rises to 2.7V */
79 DelayMs(40);
80
81 /* Set RS pin to 0 for LCD command */
82 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
83
84 /* Set RW pin to 0 for writing to LCD (If you are always writing to LCD, you
85 * can keep this pin connected to GND)
86 */
87 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
88
89 Write4Bits(0x3); /* 0 0 1 1 in D7 D6 D5 D4 order */
90
91 DelayMs(5);
92
93 Write4Bits(0x3);
94
95 DelayUs(150);
96
97 Write4Bits(0x3);
98 Write4Bits(0x2);
99
100 /* Now, ready to send the command */
101
102 /* Set to use 4 data lines, 2 lines, 5x8 char font size */
103 LCD_TxInstruction(LCD_INST_4DL_2N_5X8F);
104
105 /* Set display on, cursor on */
106 LCD_TxInstruction(LCD_INST_DON_CURON);
107
108 /* Clear display */
109 LCD_ClearDisplay();
110
111 /* Entry mode set */
112 LCD_TxInstruction(LCD_INST_INCADD);
113
114} /* End of LCD_Init */
115
116/**
117 * LCD_TxInstruction()
118 * Desc. : Sends passed instruction (@instruction) to LCD
119 * Param. : @instruction - LCD instruction to send
120 * Return : None
121 * Note : N/A
122 */
123void LCD_TxInstruction(uint8_t instruction)
124{
125 /* 1. Set RS=0 for LCD command */
126 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, RESET);
127
128 /* 2. Set RW=0 for write */
129 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
130
131 Write4Bits(instruction >> 4); /* Send the higher nibble */
132 Write4Bits(instruction & 0xF); /* Send the lower nibble */
133} /* End of LCD_TxInstruction */
134
135/**
136 * LCD_PrintChar()
137 * Desc. : Sends a character to be printed to the LCD
138 * Param. : @ch - character to print
139 * Return : None
140 * Note : This function assumes 4-bit parallel data transmission.
141 * First, the higher nibble of the data will be sent through the data
142 * lines D4, D5, d6, d7,
143 * then, the lower nibble of the data will be sent through the data
144 * lines D4, D5, d6, d7.
145 */
146void LCD_PrintChar(uint8_t ch)
147{
148 /* 1. Set RS=1 for LCD user data */
149 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RS, SET);
150
151 /* 2. Set RW=0 for write */
152 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_RW, RESET);
153
154 Write4Bits(ch >> 4); /* Send the higher nibble */
155 Write4Bits(ch & 0xF); /* Send the lower nibble */
156} /* End of LCD_TxChar */
157
158/**
159 * LCD_ClearDisplay()
160 * Desc. : Performs display clear routine
161 * Param. : None
162 * Return : None
163 * Note : After sending the clear display instruction, give it 2 ms as per
164 * the datasheet of LCD (See p.24 of LCD datasheet).
165 */
166void LCD_ClearDisplay(void)
167{
168 /* Clear display */
169 LCD_TxInstruction(LCD_INST_CLEAR_DISPLAY);
170
171 DelayMs(2); /* Wait 2 ms as per the datasheet */
172}
173
174/**
175 * LCD_ReturnHome()
176 * Desc. : Returns the cursor to the home position
177 * Param. : None
178 * Return : None
179 * Note : After sending the clear display instruction, give it 2 ms as per
180 * the datasheet of LCD (See p.24 of LCD datasheet).
181 */
182void LCD_ReturnHome(void)
183{
184 /* Return home */
185 LCD_TxInstruction(LCD_INST_RETURN_HOME);
186
187 DelayMs(2); /* Wait 2 ms as per the datasheet */
188} /* End of LCD_ReturnHome */
189
190/**
191 * LCD_PrintString()
192 * Desc. : Prints the passed string @msg to the LCD screen
193 * Param. : @msg - string to print
194 * Return : None
195 * Note : N/A
196 */
197void LCD_PrintString(char *msg)
198{
199 do
200 {
201 LCD_PrintChar((uint8_t)*msg++);
202 }
203 while (*msg != '\0');
204} /* End of LCD_PrintString */
205
206/**
207 * LCD_SetCursor()
208 * Desc. : Sets the cursor position (@row, @column)
209 * Param. : @row - the row in which the cursor should be placed
210 * @column - the column in which the cursor should be placed
211 * Return : None
212 * Note : Row number: 1 ~ 2
213 * Column number: 1 ~ 16 assuming a 2x16 character display
214 */
215void LCD_SetCursor(uint8_t row, uint8_t column)
216{
217 column--;
218
219 switch (row)
220 {
221 case 1:
222 /* Set cursor to 1st row address and add index */
223 LCD_TxInstruction((column |= 0x80));
224 break;
225 case 2:
226 /* Set cursor to 2nd row address and add index */
227 LCD_TxInstruction((column |= 0xC0));
228 break;
229 default:
230 break;
231 }
232} /* End of LCD_SetCursor */
233
234
235
236/*******************************************************************************
237 * Private functions
238 ******************************************************************************/
239
240/**
241 * DelayMs()
242 * Desc. : Spinlock delays for @delayInMs milliseconds
243 * Param. : @delayInMs - time to delay in milliseconds
244 * Returns : None
245 * Note : N/A
246 */
247static void DelayMs(uint32_t delayInMs)
248{
249 for (uint32_t i = 0; i < delayInMs * 1000; i++);
250} /* End of DelayMs */
251
252/**
253 * DelayUs()
254 * Desc. : Spinlock delays for @delayInUs microseconds
255 * Param. : @delayInUs - time to delay in microseconds
256 * Returns : None
257 * Note : N/A
258 */
259static void DelayUs(uint32_t delayInUs)
260{
261 for (uint32_t i = 0; i < delayInUs * 1; i++);
262} /* End of DelayMs */
263
264/**
265 * Write4Bits()
266 * Desc. : Writes 4 bits of data/command to D4, D5, D6, D7 lines
267 * (msb to D7, lsb to D4)
268 * Param. : @value -
269 * Return : None
270 * Note : N/A
271 */
272static void Write4Bits(uint8_t nibble)
273{
274 /* Write each bit of @nibble to D4-D7 lines */
275 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D4, (nibble >> 0) & 0x1);
276 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D5, (nibble >> 1) & 0x1);
277 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D6, (nibble >> 2) & 0x1);
278 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_D7, (nibble >> 3) & 0x1);
279
280 /* After writing every nibble to the data lines, give the LCD time to latch
281 * that data inside the LCD
282 */
283 /* Make high-to-low transition on EN pin (See the timing diagram) */
284 LCD_Enable();
285
286} /* End of Write4Bits */
287
288/**
289 * LCD_Enable()
290 * Desc. : Makes high-to-low transition on the EN line
291 * Param. : None
292 * Return : None
293 * Note : For the instruction execution time, give any value that is greater
294 * than 32 micro-seconds.
295 */
296static void LCD_Enable(void)
297{
298 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, SET);
299 DelayUs(10);
300 GPIO_WriteToOutputPin(LCD_GPIO_PORT, LCD_PIN_EN, RESET);
301 DelayUs(100);
302} /* End of LCD_Enable */