Add DMA and LiquidCrystal I2C support

- Implemented DMA functionality with a new dma.c and dma.h file.
- Added LiquidCrystal I2C driver with liquidcrystal_i2c.c and liquidcrystal_i2c.h files.
- Updated CMakeLists.txt to include dma.c and liquidcrystal_i2c.c in the build process.
- Modified build.ninja and compile_commands.json to reflect the new source files.
- Enhanced the main application to utilize the new DMA and LiquidCrystal I2C features.
This commit is contained in:
2025-05-18 16:27:45 +02:00
parent f8c5650c95
commit 344d0000fa
18 changed files with 814 additions and 105 deletions
+296
View File
@@ -0,0 +1,296 @@
#include "liquidcrystal_i2c.h"
extern I2C_HandleTypeDef hi2c1;
uint8_t dpFunction;
uint8_t dpControl;
uint8_t dpMode;
uint8_t dpRows;
uint8_t dpBacklight;
static void SendCommand(uint8_t);
static void SendChar(uint8_t);
static void Send(uint8_t, uint8_t);
static void Write4Bits(uint8_t);
static void ExpanderWrite(uint8_t);
static void PulseEnable(uint8_t);
static void DelayInit(void);
static void DelayUS(uint32_t);
uint8_t special1[8] = {
0b00000,
0b11001,
0b11011,
0b00110,
0b01100,
0b11011,
0b10011,
0b00000
};
uint8_t special2[8] = {
0b11000,
0b11000,
0b00110,
0b01001,
0b01000,
0b01001,
0b00110,
0b00000
};
void HD44780_Init(uint8_t rows)
{
dpRows = rows;
dpBacklight = LCD_BACKLIGHT;
dpFunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
if (dpRows > 1)
{
dpFunction |= LCD_2LINE;
}
else
{
dpFunction |= LCD_5x10DOTS;
}
/* Wait for initialization */
DelayInit();
HAL_Delay(50);
ExpanderWrite(dpBacklight);
HAL_Delay(1000);
/* 4bit Mode */
Write4Bits(0x03 << 4);
DelayUS(4500);
Write4Bits(0x03 << 4);
DelayUS(4500);
Write4Bits(0x03 << 4);
DelayUS(4500);
Write4Bits(0x02 << 4);
DelayUS(100);
/* Display Control */
SendCommand(LCD_FUNCTIONSET | dpFunction);
dpControl = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
HD44780_Display();
HD44780_Clear();
/* Display Mode */
dpMode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
SendCommand(LCD_ENTRYMODESET | dpMode);
DelayUS(4500);
HD44780_CreateSpecialChar(0, special1);
HD44780_CreateSpecialChar(1, special2);
HD44780_Home();
}
void HD44780_Clear()
{
SendCommand(LCD_CLEARDISPLAY);
DelayUS(2000);
}
void HD44780_Home()
{
SendCommand(LCD_RETURNHOME);
DelayUS(2000);
}
void HD44780_SetCursor(uint8_t col, uint8_t row)
{
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if (row >= dpRows)
{
row = dpRows-1;
}
SendCommand(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}
void HD44780_NoDisplay()
{
dpControl &= ~LCD_DISPLAYON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_Display()
{
dpControl |= LCD_DISPLAYON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_NoCursor()
{
dpControl &= ~LCD_CURSORON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_Cursor()
{
dpControl |= LCD_CURSORON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_NoBlink()
{
dpControl &= ~LCD_BLINKON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_Blink()
{
dpControl |= LCD_BLINKON;
SendCommand(LCD_DISPLAYCONTROL | dpControl);
}
void HD44780_ScrollDisplayLeft(void)
{
SendCommand(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void HD44780_ScrollDisplayRight(void)
{
SendCommand(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}
void HD44780_LeftToRight(void)
{
dpMode |= LCD_ENTRYLEFT;
SendCommand(LCD_ENTRYMODESET | dpMode);
}
void HD44780_RightToLeft(void)
{
dpMode &= ~LCD_ENTRYLEFT;
SendCommand(LCD_ENTRYMODESET | dpMode);
}
void HD44780_AutoScroll(void)
{
dpMode |= LCD_ENTRYSHIFTINCREMENT;
SendCommand(LCD_ENTRYMODESET | dpMode);
}
void HD44780_NoAutoScroll(void)
{
dpMode &= ~LCD_ENTRYSHIFTINCREMENT;
SendCommand(LCD_ENTRYMODESET | dpMode);
}
void HD44780_CreateSpecialChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7;
SendCommand(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
{
SendChar(charmap[i]);
}
}
void HD44780_PrintSpecialChar(uint8_t index)
{
SendChar(index);
}
void HD44780_LoadCustomCharacter(uint8_t char_num, uint8_t *rows)
{
HD44780_CreateSpecialChar(char_num, rows);
}
void HD44780_PrintStr(const char c[])
{
while(*c) SendChar(*c++);
}
void HD44780_SetBacklight(uint8_t new_val)
{
if(new_val) HD44780_Backlight();
else HD44780_NoBacklight();
}
void HD44780_NoBacklight(void)
{
dpBacklight=LCD_NOBACKLIGHT;
ExpanderWrite(0);
}
void HD44780_Backlight(void)
{
dpBacklight=LCD_BACKLIGHT;
ExpanderWrite(0);
}
static void SendCommand(uint8_t cmd)
{
Send(cmd, 0);
}
static void SendChar(uint8_t ch)
{
Send(ch, RS);
}
static void Send(uint8_t value, uint8_t mode)
{
uint8_t highnib = value & 0xF0;
uint8_t lownib = (value<<4) & 0xF0;
Write4Bits((highnib)|mode);
Write4Bits((lownib)|mode);
}
static void Write4Bits(uint8_t value)
{
ExpanderWrite(value);
PulseEnable(value);
}
static void ExpanderWrite(uint8_t _data)
{
uint8_t data = _data | dpBacklight;
HAL_I2C_Master_Transmit(&hi2c1, DEVICE_ADDR, (uint8_t*)&data, 1, 10);
}
static void PulseEnable(uint8_t _data)
{
ExpanderWrite(_data | ENABLE);
DelayUS(20);
ExpanderWrite(_data & ~ENABLE);
DelayUS(20);
}
static void DelayInit(void)
{
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; //~0x00000001;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; //0x00000001;
DWT->CYCCNT = 0;
/* 3 NO OPERATION instructions */
__ASM volatile ("NOP");
__ASM volatile ("NOP");
__ASM volatile ("NOP");
}
static void DelayUS(uint32_t us) {
uint32_t cycles = (SystemCoreClock/1000000L)*us;
uint32_t start = DWT->CYCCNT;
volatile uint32_t cnt;
do
{
cnt = DWT->CYCCNT - start;
} while(cnt < cycles);
}