Browse code

Add source code of the firmware for the IO Board

Pawel Jablonski authored on 05/06/2023 17:01:27
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,607 @@
1
+/*
2
+ * Author: Pawel Jablonski
3
+ * E-mail: pj@xirx.net
4
+ * WWW: xirx.net
5
+ * GIT: git.xirx.net
6
+ *
7
+ * License: You can use this code however you like
8
+ * but leave information about the original author.
9
+ * Code is free for non-commercial and commercial use.
10
+ */
11
+
12
+#include <stm32f0xx.h>
13
+#include <stm32f0xx_hal.h>
14
+#include <stm32f0xx_hal_gpio.h>
15
+#include <stm32f0xx_hal_rcc.h>
16
+#include <system_stm32f0xx.h>
17
+
18
+#include "type.h"
19
+#include "keyboard.h"
20
+#include "led.h"
21
+#include "lcd.h"
22
+#include "rs232.h"
23
+#include "rtc.h"
24
+#include "speaker.h"
25
+#include "fs.h"
26
+
27
+#include "io.h"
28
+
29
+//!< List of motherboard's virtual registers
30
+enum IORegAddress
31
+{
32
+	IO_REG_KEYBOARD = 0, //!< Keyboard register
33
+	IO_REG_LED_COMMAND = 1, //!< LED register
34
+	IO_REG_ADDRESS_LOW = 2, //!< Lower address register
35
+	IO_REG_ADDRESS_HIGH = 3, //!< Upper address register
36
+	IO_REG_LCD_COLOR = 4, //!< LCD color register
37
+	IO_REG_LCD_CHAR = 5, //!< LCD char register
38
+	IO_REG_LCD_COMMAND = 6, //!< LCD command register
39
+	IO_REG_RS232_RX = 7, //!< RS232 receive register
40
+	IO_REG_RS232_TX = 8, //!< RS232 transmit register
41
+	IO_REG_RTC_FIELD = 9, //!< Real Time Clock data register
42
+	IO_REG_RTC_COMMAND = 10, //!< Real Time Clock command register
43
+	IO_REG_SPEAKER_FIELD = 11, //!< Speaker data register
44
+	IO_REG_SPEAKER_COMMAND = 12, //!< Speaker command register
45
+	IO_REG_FS_NAME = 13, //!< File System name register
46
+	IO_REG_FS_DATA = 14, //!< File System data register
47
+	IO_REG_FS_COMMAND = 15 //!< File System command register
48
+};
49
+
50
+//!< List of LED commands
51
+enum IOLedCommand
52
+{
53
+	IO_LED_RUN_OFF = 0, //!< Turn off run LED
54
+	IO_LED_RUN_ON, //!< Turn on run LED
55
+	IO_LED_ERROR_OFF, //!< Turn off error LED
56
+	IO_LED_ERROR_ON //!< Turn on error LED
57
+};
58
+
59
+//!< List of LCD commands
60
+enum IOLcdCommand
61
+{
62
+	IO_LCD_CLEAR = 0, //!< Clear the screen
63
+	IO_LCD_REFRESH, //!< Refresh the screen using data from the framebuffer
64
+	IO_LCD_SCROLL //!< Scroll up one line up the screen
65
+};
66
+
67
+//!< List of Real Time Clock fields
68
+enum IORtcField
69
+{
70
+	IO_RTC_YEAR = 0, //!< Year
71
+	IO_RTC_MONTH, //!< Month
72
+	IO_RTC_DAY, //!< Day
73
+	IO_RTC_HOUR, //!< Hour
74
+	IO_RTC_MINUTE, //!< Minute
75
+	IO_RTC_SECOND //!< Second
76
+};
77
+
78
+//!< List of Real Time Clock commands
79
+enum IORtcCommand
80
+{
81
+	IO_RTC_READ = 0, //!< Read current date and time
82
+	IO_RTC_WRITE //!< Set current date and time
83
+};
84
+
85
+//!< List of Speaker fields
86
+enum IOSpeakerField
87
+{
88
+	IO_SPEAKER_NOTE = 0, //!< Note number
89
+	IO_SPEAKER_TIME, //!< Time to play
90
+	IO_SPEAKER_FILL, //!< Percentage fill of the square wave
91
+	IO_SPEAKER_VOLUME //!< Volume
92
+};
93
+
94
+//!< List of Speaker commands
95
+enum IOSpeakerCommand
96
+{
97
+	IO_SPEAKER_CLEAR = 0, //!< Stop playing and clear the buffer
98
+	IO_SPEAKER_ADD_NOTE, //!< Add note to the buffer and play it
99
+};
100
+
101
+//!< List of File System commands
102
+enum IOFSCommand
103
+{
104
+	IO_FS_OPEN_APP = 0, //!< Open an application
105
+	IO_FS_OPEN_FILE, //!< Open a file
106
+	IO_FS_LIST_APP, //!< List all applications
107
+	IO_FS_LIST_FILE, //!< List all files
108
+	IO_FS_SIZE, //!< Get size of the file
109
+	IO_FS_READ_BLOCK //!< Read data from the block
110
+};
111
+
112
+//!< This struct cointains a memory adddress
113
+struct IOAddress
114
+{
115
+	unsigned char low; //!< Lower byte of the address
116
+	unsigned char high; //!< Upper byte of the address
117
+};
118
+
119
+static unsigned char regSelected = 0x00; //!< Selected virtual register number
120
+
121
+//!< This struct contains motherboard's virtual registers buffer
122
+struct
123
+{
124
+	unsigned char keyboard; //!< Keyboard buffer
125
+	struct IOAddress address; //!< Address buffer
126
+	unsigned char lcdForegroundColor; //!< LCD foreground color buffer
127
+	unsigned char lcdBackgroundColor; //!< LCD background color buffer
128
+	unsigned char lcdChar; //!< LCD char buffer
129
+	unsigned char rs232Rx; //!< RS232 receive buffer
130
+	unsigned char rs232Tx; //!< RS232 transmit bufffer
131
+	unsigned char rs232TxBufferFree; //!< RS232 transmit free space in buffer counter
132
+	struct RTCDateTime rtcField; //!< Real Time Clock buffer
133
+	struct SpeakerNote speakerField; //!< Speaker buffer
134
+	unsigned char speakerBufferFree; //!< Speaker free space in buffer counter
135
+	struct FSName fsName; //!< File System name buffer
136
+	struct FSSize fsSize; //!< File System size buffer
137
+	struct FSBlock fsBlock; //!< File System data block buffer
138
+} static reg;
139
+
140
+
141
+//! First stage of init. It set up all IO pins. It must be executed before all devices init.
142
+void ioPreInit(void)
143
+{
144
+	GPIO_InitTypeDef gpioInit = {0};
145
+	
146
+	__HAL_RCC_GPIOB_CLK_ENABLE();
147
+	
148
+	gpioInit.Pin = (GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
149
+	gpioInit.Mode = GPIO_MODE_INPUT;
150
+	gpioInit.Pull = GPIO_PULLDOWN;
151
+	gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
152
+	
153
+	HAL_GPIO_Init(GPIOB, &gpioInit);
154
+	
155
+	gpioInit.Pin = (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
156
+	gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
157
+	gpioInit.Pull = GPIO_NOPULL;
158
+	gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
159
+	
160
+	HAL_GPIO_Init(GPIOB, &gpioInit);
161
+	
162
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
163
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
164
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
165
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
166
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
167
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
168
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
169
+	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
170
+}
171
+
172
+//! Second stage of init. It set up the IRQ used in IO communication. I can only be executed when all devices are inited.
173
+void ioInit(void)
174
+{
175
+	GPIO_InitTypeDef gpioInit = {0};
176
+	
177
+	gpioInit.Pin = GPIO_PIN_15;
178
+	gpioInit.Mode = GPIO_MODE_IT_RISING;
179
+	gpioInit.Pull = GPIO_PULLDOWN;
180
+	gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
181
+	
182
+	HAL_GPIO_Init(GPIOB, &gpioInit);
183
+
184
+	HAL_NVIC_SetPriority(EXTI4_15_IRQn, 4, 0);
185
+	HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
186
+}
187
+
188
+//! Process the IO clock fire event. Toggle the clock pin.
189
+void ioFireClock(void)
190
+{
191
+	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
192
+}
193
+
194
+//! Process the IO peripherial fire event. Check if the keyboard or the rs232 have a new data in the buffers.
195
+void ioFirePeripherial(void)
196
+{
197
+	if(keyboardIsData())
198
+	{
199
+		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
200
+	}
201
+	else
202
+	{
203
+		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
204
+	}
205
+	
206
+	if(rs232RxIsData())
207
+	{
208
+		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
209
+	}
210
+	else
211
+	{
212
+		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
213
+	}
214
+}
215
+
216
+//! Process the IRQ event for the IO. It processes a new incoming request from the XiPU.
217
+void EXTI4_15_IRQHandler(void)
218
+{
219
+	if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_15) != RESET) 
220
+	{
221
+		unsigned char value = ((GPIOB->IDR >> 8) & 0xff);
222
+		
223
+		unsigned char half = (value & (1 << 4));
224
+		unsigned char mode = (value & (1 << 5));
225
+		unsigned char rw = (value & (1 << 6));
226
+
227
+		if(!mode)
228
+		{
229
+			// Select register to work
230
+			regSelected = (value & IO_REG_SELECT_MASK);
231
+		}
232
+		else
233
+		{
234
+			if(!rw)
235
+			{
236
+				unsigned char dataOut = 0x00;
237
+
238
+				// Read register value
239
+				switch(regSelected)
240
+				{
241
+					case IO_REG_KEYBOARD :
242
+						{
243
+							if(!half)
244
+							{
245
+								reg.keyboard = keyboardGetKey();
246
+								
247
+								if(!keyboardIsData())
248
+								{
249
+									HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
250
+								}
251
+							}
252
+
253
+							dataOut = reg.keyboard;
254
+						}
255
+						break;
256
+
257
+					case IO_REG_RS232_RX :
258
+						{
259
+							if(!half)
260
+							{
261
+								reg.rs232Rx = rs232Receive();
262
+								
263
+								if(!rs232RxIsData())
264
+								{
265
+									HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
266
+								}
267
+							}
268
+
269
+							dataOut = reg.rs232Rx;
270
+						}
271
+						break;
272
+
273
+					case IO_REG_RTC_FIELD :
274
+						switch(reg.address.low)
275
+						{
276
+							case IO_RTC_YEAR :
277
+								dataOut = reg.rtcField.year;
278
+								break;
279
+
280
+							case IO_RTC_MONTH :
281
+								dataOut = reg.rtcField.month;
282
+								break;
283
+
284
+							case IO_RTC_DAY :
285
+								dataOut = reg.rtcField.day;
286
+								break;
287
+
288
+							case IO_RTC_HOUR :
289
+								dataOut = reg.rtcField.hour;
290
+								break;
291
+
292
+							case IO_RTC_MINUTE :
293
+								dataOut = reg.rtcField.minute;
294
+								break;
295
+
296
+							case IO_RTC_SECOND :
297
+								dataOut = reg.rtcField.second;
298
+								break;
299
+
300
+							default :
301
+								dataOut = 0;
302
+								break;
303
+						}
304
+						break;
305
+
306
+					case IO_REG_SPEAKER_FIELD :
307
+						{
308
+							if(!half)
309
+							{
310
+								reg.speakerBufferFree = speakerGetBufferFree();
311
+							}
312
+
313
+							dataOut = reg.speakerBufferFree;
314
+						}
315
+						break;
316
+
317
+					case IO_REG_FS_DATA :
318
+						{
319
+							dataOut = reg.fsBlock.data[reg.address.low];
320
+
321
+							if(half)
322
+							{
323
+								reg.address.low++;
324
+							}
325
+						}
326
+						break;
327
+
328
+					case IO_REG_FS_COMMAND :
329
+						switch(reg.address.low)
330
+						{
331
+							case IO_FS_OPEN_APP :
332
+								{
333
+									reg.fsName.data[FS_NAME_MAX_LENGTH] = 0;
334
+
335
+									if(fsOpen("app", &(reg.fsName), &(reg.fsSize)))
336
+									{
337
+										dataOut = 1;
338
+									}
339
+									else
340
+									{
341
+										dataOut = 0;
342
+									}
343
+								}
344
+								break;
345
+
346
+							case IO_FS_OPEN_FILE :
347
+								{
348
+									reg.fsName.data[FS_NAME_MAX_LENGTH] = 0;
349
+
350
+									if(fsOpen("file", &(reg.fsName), &(reg.fsSize)))
351
+									{
352
+										dataOut = 1;
353
+									}
354
+									else
355
+									{
356
+										dataOut = 0;
357
+									}
358
+								}
359
+								break;
360
+
361
+							case IO_FS_LIST_APP :
362
+								{
363
+									if(fsList("app", &(reg.fsSize)))
364
+									{
365
+										dataOut = 1;
366
+									}
367
+									else
368
+									{
369
+										dataOut = 0;
370
+									}
371
+								}
372
+								break;
373
+
374
+							case IO_FS_LIST_FILE :
375
+								{
376
+									if(fsList("file", &(reg.fsSize)))
377
+									{
378
+										dataOut = 1;
379
+									}
380
+									else
381
+									{
382
+										dataOut = 0;
383
+									}
384
+								}
385
+								break;
386
+
387
+							case IO_FS_SIZE :
388
+								switch(reg.address.high)
389
+								{
390
+									case 0 :
391
+										dataOut = reg.fsSize.low;
392
+										break;
393
+
394
+									case 1 :
395
+										dataOut = reg.fsSize.high;
396
+										break;
397
+
398
+									default:
399
+										dataOut = 0;
400
+										break;
401
+								}
402
+								break;
403
+
404
+							default :
405
+								dataOut = 0;
406
+								break;
407
+						}
408
+						break;
409
+
410
+					default :
411
+						dataOut = 0;
412
+						break;
413
+				}
414
+
415
+				if(half)
416
+				{
417
+					dataOut >>= 4;
418
+				}
419
+
420
+				// Register value to out
421
+				GPIOB->ODR = ((GPIOB->ODR & IO_IN_CONTROL_MASK) | (dataOut & IO_IN_DATA_MASK));
422
+			}
423
+			else
424
+			{
425
+				unsigned char dataInRaw = (value & IO_IN_DATA_MASK);
426
+				unsigned char dataIn = dataInRaw;
427
+				unsigned char mask = IO_HALF_UP_DATA_MASK;
428
+
429
+				if(half)
430
+				{
431
+					dataIn <<= IO_HALF_DATA_OFFSET;
432
+					mask >>= IO_HALF_DATA_OFFSET;
433
+				}
434
+
435
+				// Write register value
436
+				switch(regSelected)
437
+				{
438
+					case IO_REG_LED_COMMAND :
439
+						switch(dataInRaw)
440
+						{
441
+							case IO_LED_RUN_OFF :
442
+								ledSetRun(FALSE);
443
+								break;
444
+							case IO_LED_RUN_ON :
445
+								ledSetRun(TRUE);
446
+								break;
447
+							case IO_LED_ERROR_OFF :
448
+								ledSetError(FALSE);
449
+								break;
450
+							case IO_LED_ERROR_ON :
451
+								ledSetError(TRUE);
452
+								break;
453
+						}
454
+						break;
455
+
456
+					case IO_REG_ADDRESS_LOW :
457
+						reg.address.low = ((reg.address.low & mask) | dataIn);
458
+						break;
459
+
460
+					case IO_REG_ADDRESS_HIGH :
461
+						reg.address.high = ((reg.address.high & mask) | dataIn);
462
+						break;
463
+
464
+					case IO_REG_LCD_COLOR :
465
+						if(!half)
466
+						{
467
+							reg.lcdForegroundColor = dataInRaw;
468
+						}
469
+						else
470
+						{
471
+							reg.lcdBackgroundColor = dataInRaw;
472
+						}
473
+						break;
474
+
475
+					case IO_REG_LCD_CHAR :
476
+						reg.lcdChar = ((reg.lcdChar & mask) | dataIn);
477
+						if(half)
478
+						{
479
+							lcdSetChar(reg.lcdChar, reg.address.low, reg.address.high, reg.lcdForegroundColor, reg.lcdBackgroundColor);
480
+						}
481
+						break;
482
+
483
+					case IO_REG_LCD_COMMAND :
484
+						switch(dataIn)
485
+						{
486
+							case IO_LCD_CLEAR :
487
+								lcdClear();
488
+								lcdRefresh();
489
+								break;
490
+							case IO_LCD_REFRESH :
491
+								lcdRefresh();
492
+								break;
493
+							case IO_LCD_SCROLL :
494
+								lcdScroll();
495
+								break;
496
+						}
497
+						break;
498
+
499
+					case IO_REG_RS232_TX :
500
+						reg.rs232Tx = ((reg.rs232Tx & mask) | dataIn);
501
+						if(half)
502
+						{
503
+							rs232Send(reg.rs232Tx);
504
+						}
505
+						break;
506
+
507
+					case IO_REG_RTC_FIELD :
508
+						switch(reg.address.low)
509
+						{
510
+							case IO_RTC_YEAR :
511
+								reg.rtcField.year = ((reg.rtcField.year & mask) | dataIn);
512
+								break;
513
+
514
+							case IO_RTC_MONTH :
515
+								reg.rtcField.month = ((reg.rtcField.month & mask) | dataIn);
516
+								break;
517
+
518
+							case IO_RTC_DAY :
519
+								reg.rtcField.day = ((reg.rtcField.day & mask) | dataIn);
520
+								break;
521
+
522
+							case IO_RTC_HOUR :
523
+								reg.rtcField.hour = ((reg.rtcField.hour & mask) | dataIn);
524
+								break;
525
+
526
+							case IO_RTC_MINUTE :
527
+								reg.rtcField.minute = ((reg.rtcField.minute & mask) | dataIn);
528
+								break;
529
+
530
+							case IO_RTC_SECOND :
531
+								reg.rtcField.second = ((reg.rtcField.second & mask) | dataIn);
532
+								break;
533
+						}
534
+						break;
535
+
536
+					case IO_REG_RTC_COMMAND :
537
+						switch(dataInRaw)
538
+						{
539
+							case IO_RTC_READ :
540
+								reg.rtcField = rtcGetDateTime();
541
+								break;
542
+
543
+							case IO_RTC_WRITE :
544
+								rtcSetDateTime(reg.rtcField);
545
+								break;
546
+						}
547
+						break;
548
+
549
+					case IO_REG_SPEAKER_FIELD :
550
+						switch(reg.address.low)
551
+						{
552
+							case IO_SPEAKER_NOTE :
553
+								reg.speakerField.note = ((reg.speakerField.note & mask) | dataIn);
554
+								break;
555
+
556
+							case IO_SPEAKER_TIME :
557
+								reg.speakerField.time = ((reg.speakerField.time & mask) | dataIn);
558
+								break;
559
+
560
+							case IO_SPEAKER_FILL :
561
+								reg.speakerField.fill = dataInRaw;
562
+								break;
563
+
564
+							case IO_SPEAKER_VOLUME :
565
+								reg.speakerField.volume = dataInRaw;
566
+								break;
567
+						}
568
+						break;
569
+
570
+					case IO_REG_SPEAKER_COMMAND :
571
+						switch(dataInRaw)
572
+						{
573
+							case IO_SPEAKER_CLEAR :
574
+								speakerClear();
575
+								break;
576
+
577
+							case IO_SPEAKER_ADD_NOTE :
578
+								speakerAddNote(reg.speakerField);
579
+								break;
580
+						}
581
+						break;
582
+
583
+					case IO_REG_FS_NAME :
584
+						if(reg.address.low < FS_NAME_MAX_LENGTH)
585
+						{
586
+							reg.fsName.data[reg.address.low] = ((reg.fsName.data[reg.address.low] & mask) | dataIn);
587
+						}
588
+						break;
589
+
590
+					case IO_REG_FS_COMMAND :
591
+						switch(dataInRaw)
592
+						{
593
+							case IO_FS_READ_BLOCK :
594
+								fsReadBlock(&(reg.fsBlock), reg.address.low);
595
+								break;
596
+						}
597
+						break;
598
+				}
599
+			}
600
+		}
601
+		
602
+		__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_15);
603
+		
604
+		// Operation is completed
605
+		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
606
+	}
607
+}