mirror of
https://gitee.com/dlmu-cone/tronone-h7-scaffold
synced 2026-07-23 19:25:09 +08:00
ioc changed but not tested
This commit is contained in:
552
User_Code/module/periph/tft/tft.c
Normal file
552
User_Code/module/periph/tft/tft.c
Normal file
@@ -0,0 +1,552 @@
|
||||
#include "tft.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TFT_SPI_TIMEOUT_MS 100U
|
||||
#define TFT_FONT_W 5U
|
||||
#define TFT_FONT_H 7U
|
||||
#define TFT_MAX_SCALE 4U
|
||||
|
||||
#if (TFT_USE_HORIZONTAL == 0U) || (TFT_USE_HORIZONTAL == 1U)
|
||||
#define TFT_X_OFFSET 0U
|
||||
#define TFT_Y_OFFSET 20U
|
||||
#else
|
||||
#define TFT_X_OFFSET 20U
|
||||
#define TFT_Y_OFFSET 0U
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TFT_GLYPH_SPACE = 0,
|
||||
TFT_GLYPH_DASH,
|
||||
TFT_GLYPH_DOT,
|
||||
TFT_GLYPH_COLON,
|
||||
TFT_GLYPH_0,
|
||||
TFT_GLYPH_A = TFT_GLYPH_0 + 10
|
||||
} TFT_GlyphIndex_e;
|
||||
|
||||
static bool tft_initialized = false;
|
||||
|
||||
static const uint8_t tft_font5x7[][TFT_FONT_H] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* space */
|
||||
{0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00}, /* - */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C}, /* . */
|
||||
{0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, /* : */
|
||||
{0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E}, /* 0 */
|
||||
{0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E}, /* 1 */
|
||||
{0x0E, 0x11, 0x10, 0x08, 0x04, 0x02, 0x1F}, /* 2 */
|
||||
{0x1F, 0x08, 0x04, 0x08, 0x10, 0x11, 0x0E}, /* 3 */
|
||||
{0x08, 0x0C, 0x0A, 0x09, 0x1F, 0x08, 0x08}, /* 4 */
|
||||
{0x1F, 0x01, 0x0F, 0x10, 0x10, 0x11, 0x0E}, /* 5 */
|
||||
{0x0C, 0x02, 0x01, 0x0F, 0x11, 0x11, 0x0E}, /* 6 */
|
||||
{0x1F, 0x10, 0x08, 0x04, 0x02, 0x02, 0x02}, /* 7 */
|
||||
{0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E}, /* 8 */
|
||||
{0x0E, 0x11, 0x11, 0x1E, 0x10, 0x08, 0x06}, /* 9 */
|
||||
{0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, /* A */
|
||||
{0x0F, 0x11, 0x11, 0x0F, 0x11, 0x11, 0x0F}, /* B */
|
||||
{0x0E, 0x11, 0x01, 0x01, 0x01, 0x11, 0x0E}, /* C */
|
||||
{0x0F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0F}, /* D */
|
||||
{0x1F, 0x01, 0x01, 0x0F, 0x01, 0x01, 0x1F}, /* E */
|
||||
{0x1F, 0x01, 0x01, 0x0F, 0x01, 0x01, 0x01}, /* F */
|
||||
{0x0E, 0x11, 0x01, 0x1D, 0x11, 0x11, 0x0E}, /* G */
|
||||
{0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, /* H */
|
||||
{0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E}, /* I */
|
||||
{0x1C, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06}, /* J */
|
||||
{0x11, 0x09, 0x05, 0x03, 0x05, 0x09, 0x11}, /* K */
|
||||
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F}, /* L */
|
||||
{0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11}, /* M */
|
||||
{0x11, 0x13, 0x15, 0x19, 0x11, 0x11, 0x11}, /* N */
|
||||
{0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, /* O */
|
||||
{0x0F, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x01}, /* P */
|
||||
{0x0E, 0x11, 0x11, 0x11, 0x15, 0x09, 0x16}, /* Q */
|
||||
{0x0F, 0x11, 0x11, 0x0F, 0x05, 0x09, 0x11}, /* R */
|
||||
{0x1E, 0x01, 0x01, 0x0E, 0x10, 0x10, 0x0F}, /* S */
|
||||
{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, /* T */
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, /* U */
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04}, /* V */
|
||||
{0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A}, /* W */
|
||||
{0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11}, /* X */
|
||||
{0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04}, /* Y */
|
||||
{0x1F, 0x10, 0x08, 0x04, 0x02, 0x01, 0x1F}, /* Z */
|
||||
};
|
||||
|
||||
static void tft_cs_low(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_CS_GPIO_Port, TFT_CS_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
static void tft_cs_high(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_CS_GPIO_Port, TFT_CS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void tft_dc_command(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_DC_GPIO_Port, TFT_DC_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
static void tft_dc_data(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_DC_GPIO_Port, TFT_DC_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void tft_reset_low(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_RES_GPIO_Port, TFT_RES_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
static void tft_reset_high(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_RES_GPIO_Port, TFT_RES_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void tft_backlight_on(void)
|
||||
{
|
||||
HAL_GPIO_WritePin(TFT_BLK_GPIO_Port, TFT_BLK_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void tft_write_bytes(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
while (len > 0U)
|
||||
{
|
||||
uint16_t chunk = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
|
||||
(void) HAL_SPI_Transmit(&TFT_SPI_UNIT, (uint8_t *) data, chunk, TFT_SPI_TIMEOUT_MS);
|
||||
data += chunk;
|
||||
len -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
static void lcd_write_reg(uint8_t reg)
|
||||
{
|
||||
tft_cs_low();
|
||||
tft_dc_command();
|
||||
tft_write_bytes(®, 1U);
|
||||
tft_cs_high();
|
||||
}
|
||||
|
||||
static void lcd_write_data8(uint8_t data)
|
||||
{
|
||||
tft_cs_low();
|
||||
tft_dc_data();
|
||||
tft_write_bytes(&data, 1U);
|
||||
tft_cs_high();
|
||||
}
|
||||
|
||||
static void lcd_write_data16(uint16_t data)
|
||||
{
|
||||
uint8_t buf[2] = {(uint8_t) (data >> 8), (uint8_t) data};
|
||||
tft_cs_low();
|
||||
tft_dc_data();
|
||||
tft_write_bytes(buf, sizeof(buf));
|
||||
tft_cs_high();
|
||||
}
|
||||
|
||||
static void tft_write_color_block(uint16_t color, uint32_t count)
|
||||
{
|
||||
uint8_t buf[64];
|
||||
uint8_t high = (uint8_t) (color >> 8);
|
||||
uint8_t low = (uint8_t) color;
|
||||
|
||||
for (uint32_t i = 0U; i < sizeof(buf); i += 2U)
|
||||
{
|
||||
buf[i] = high;
|
||||
buf[i + 1U] = low;
|
||||
}
|
||||
|
||||
tft_cs_low();
|
||||
tft_dc_data();
|
||||
while (count > 0U)
|
||||
{
|
||||
uint32_t pixels = count > (sizeof(buf) / 2U) ? (sizeof(buf) / 2U) : count;
|
||||
tft_write_bytes(buf, pixels * 2U);
|
||||
count -= pixels;
|
||||
}
|
||||
tft_cs_high();
|
||||
}
|
||||
|
||||
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
|
||||
{
|
||||
uint16_t xs = x1 + TFT_X_OFFSET;
|
||||
uint16_t xe = x2 + TFT_X_OFFSET;
|
||||
uint16_t ys = y1 + TFT_Y_OFFSET;
|
||||
uint16_t ye = y2 + TFT_Y_OFFSET;
|
||||
|
||||
lcd_write_reg(0x2A);
|
||||
lcd_write_data16(xs);
|
||||
lcd_write_data16(xe);
|
||||
lcd_write_reg(0x2B);
|
||||
lcd_write_data16(ys);
|
||||
lcd_write_data16(ye);
|
||||
lcd_write_reg(0x2C);
|
||||
}
|
||||
|
||||
void TFT_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
|
||||
{
|
||||
if (x >= TFT_LCD_W || y >= TFT_LCD_H || width == 0U || height == 0U)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((uint32_t) x + width > TFT_LCD_W)
|
||||
{
|
||||
width = (uint16_t) (TFT_LCD_W - x);
|
||||
}
|
||||
if ((uint32_t) y + height > TFT_LCD_H)
|
||||
{
|
||||
height = (uint16_t) (TFT_LCD_H - y);
|
||||
}
|
||||
|
||||
LCD_Address_Set(x, y, (uint16_t) (x + width - 1U), (uint16_t) (y + height - 1U));
|
||||
tft_write_color_block(color, (uint32_t) width * height);
|
||||
}
|
||||
|
||||
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
|
||||
{
|
||||
if (xend <= xsta || yend <= ysta)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TFT_FillRect(xsta, ysta, (uint16_t) (xend - xsta), (uint16_t) (yend - ysta), color);
|
||||
}
|
||||
|
||||
void TFT_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
TFT_FillRect(x, y, 1U, 1U, color);
|
||||
}
|
||||
|
||||
static const uint8_t *tft_get_glyph(char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
{
|
||||
ch = (char) (ch - ('a' - 'A'));
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9')
|
||||
{
|
||||
return tft_font5x7[TFT_GLYPH_0 + (uint8_t) (ch - '0')];
|
||||
}
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
{
|
||||
return tft_font5x7[TFT_GLYPH_A + (uint8_t) (ch - 'A')];
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '-':
|
||||
return tft_font5x7[TFT_GLYPH_DASH];
|
||||
case '.':
|
||||
return tft_font5x7[TFT_GLYPH_DOT];
|
||||
case ':':
|
||||
return tft_font5x7[TFT_GLYPH_COLON];
|
||||
default:
|
||||
return tft_font5x7[TFT_GLYPH_SPACE];
|
||||
}
|
||||
}
|
||||
|
||||
static void tft_draw_char(uint16_t x, uint16_t y, char ch, uint16_t fc, uint16_t bc, uint8_t scale)
|
||||
{
|
||||
uint8_t line[(TFT_FONT_W * TFT_MAX_SCALE) * 2U];
|
||||
const uint8_t *glyph;
|
||||
uint16_t char_w;
|
||||
uint16_t char_h;
|
||||
|
||||
if (scale == 0U)
|
||||
{
|
||||
scale = 1U;
|
||||
}
|
||||
if (scale > TFT_MAX_SCALE)
|
||||
{
|
||||
scale = TFT_MAX_SCALE;
|
||||
}
|
||||
|
||||
char_w = TFT_FONT_W * scale;
|
||||
char_h = TFT_FONT_H * scale;
|
||||
if (x >= TFT_LCD_W || y >= TFT_LCD_H)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glyph = tft_get_glyph(ch);
|
||||
LCD_Address_Set(x, y, (uint16_t) (x + char_w - 1U), (uint16_t) (y + char_h - 1U));
|
||||
|
||||
tft_cs_low();
|
||||
tft_dc_data();
|
||||
for (uint8_t row = 0U; row < TFT_FONT_H; row++)
|
||||
{
|
||||
for (uint8_t repeat_y = 0U; repeat_y < scale; repeat_y++)
|
||||
{
|
||||
uint32_t idx = 0U;
|
||||
for (uint8_t col = 0U; col < TFT_FONT_W; col++)
|
||||
{
|
||||
uint16_t color = (glyph[row] & (1U << (TFT_FONT_W - 1U - col))) ? fc : bc;
|
||||
for (uint8_t repeat_x = 0U; repeat_x < scale; repeat_x++)
|
||||
{
|
||||
line[idx++] = (uint8_t) (color >> 8);
|
||||
line[idx++] = (uint8_t) color;
|
||||
}
|
||||
}
|
||||
tft_write_bytes(line, idx);
|
||||
}
|
||||
}
|
||||
tft_cs_high();
|
||||
}
|
||||
|
||||
void TFT_DrawString(uint16_t x, uint16_t y, const char *text, uint16_t fc, uint16_t bc, uint8_t scale)
|
||||
{
|
||||
uint16_t cursor = x;
|
||||
uint16_t advance;
|
||||
|
||||
if (text == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (scale == 0U)
|
||||
{
|
||||
scale = 1U;
|
||||
}
|
||||
if (scale > TFT_MAX_SCALE)
|
||||
{
|
||||
scale = TFT_MAX_SCALE;
|
||||
}
|
||||
|
||||
advance = (TFT_FONT_W + 1U) * scale;
|
||||
while (*text != '\0')
|
||||
{
|
||||
if (cursor + (TFT_FONT_W * scale) >= TFT_LCD_W)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
tft_draw_char(cursor, y, *text, fc, bc, scale);
|
||||
cursor = (uint16_t) (cursor + advance);
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
void TFT_Clear(uint16_t color)
|
||||
{
|
||||
LCD_Fill(0U, 0U, TFT_LCD_W, TFT_LCD_H, color);
|
||||
}
|
||||
|
||||
void LCD_Init(void)
|
||||
{
|
||||
if (tft_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tft_cs_high();
|
||||
tft_reset_low();
|
||||
HAL_Delay(100);
|
||||
tft_reset_high();
|
||||
HAL_Delay(100);
|
||||
|
||||
tft_backlight_on();
|
||||
HAL_Delay(100);
|
||||
|
||||
lcd_write_reg(0x11);
|
||||
HAL_Delay(120);
|
||||
|
||||
lcd_write_reg(0x36);
|
||||
#if TFT_USE_HORIZONTAL == 0U
|
||||
lcd_write_data8(0x00);
|
||||
#elif TFT_USE_HORIZONTAL == 1U
|
||||
lcd_write_data8(0xC0);
|
||||
#elif TFT_USE_HORIZONTAL == 2U
|
||||
lcd_write_data8(0x70);
|
||||
#else
|
||||
lcd_write_data8(0xA0);
|
||||
#endif
|
||||
|
||||
lcd_write_reg(0x3A);
|
||||
lcd_write_data8(0x05);
|
||||
|
||||
lcd_write_reg(0xB2);
|
||||
lcd_write_data8(0x0C);
|
||||
lcd_write_data8(0x0C);
|
||||
lcd_write_data8(0x00);
|
||||
lcd_write_data8(0x33);
|
||||
lcd_write_data8(0x33);
|
||||
|
||||
lcd_write_reg(0xB7);
|
||||
lcd_write_data8(0x35);
|
||||
|
||||
lcd_write_reg(0xBB);
|
||||
lcd_write_data8(0x32);
|
||||
|
||||
lcd_write_reg(0xC2);
|
||||
lcd_write_data8(0x01);
|
||||
|
||||
lcd_write_reg(0xC3);
|
||||
lcd_write_data8(0x15);
|
||||
|
||||
lcd_write_reg(0xC4);
|
||||
lcd_write_data8(0x20);
|
||||
|
||||
lcd_write_reg(0xC6);
|
||||
lcd_write_data8(0x0F);
|
||||
|
||||
lcd_write_reg(0xD0);
|
||||
lcd_write_data8(0xA4);
|
||||
lcd_write_data8(0xA1);
|
||||
|
||||
lcd_write_reg(0xE0);
|
||||
lcd_write_data8(0xD0);
|
||||
lcd_write_data8(0x08);
|
||||
lcd_write_data8(0x0E);
|
||||
lcd_write_data8(0x09);
|
||||
lcd_write_data8(0x09);
|
||||
lcd_write_data8(0x05);
|
||||
lcd_write_data8(0x31);
|
||||
lcd_write_data8(0x33);
|
||||
lcd_write_data8(0x48);
|
||||
lcd_write_data8(0x17);
|
||||
lcd_write_data8(0x14);
|
||||
lcd_write_data8(0x15);
|
||||
lcd_write_data8(0x31);
|
||||
lcd_write_data8(0x34);
|
||||
|
||||
lcd_write_reg(0xE1);
|
||||
lcd_write_data8(0xD0);
|
||||
lcd_write_data8(0x08);
|
||||
lcd_write_data8(0x0E);
|
||||
lcd_write_data8(0x09);
|
||||
lcd_write_data8(0x09);
|
||||
lcd_write_data8(0x15);
|
||||
lcd_write_data8(0x31);
|
||||
lcd_write_data8(0x33);
|
||||
lcd_write_data8(0x48);
|
||||
lcd_write_data8(0x17);
|
||||
lcd_write_data8(0x14);
|
||||
lcd_write_data8(0x15);
|
||||
lcd_write_data8(0x31);
|
||||
lcd_write_data8(0x34);
|
||||
|
||||
lcd_write_reg(0x21);
|
||||
lcd_write_reg(0x29);
|
||||
|
||||
tft_initialized = true;
|
||||
TFT_Clear(TFT_COLOR_BLACK);
|
||||
}
|
||||
|
||||
void TFT_Init(void)
|
||||
{
|
||||
LCD_Init();
|
||||
}
|
||||
|
||||
const char *TFT_RobotModeText(RobotMode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case NORMAL_MODE:
|
||||
return "NORMAL";
|
||||
case SYS_ERROR_OCCURRED:
|
||||
return "ERROR";
|
||||
case REMOTE_NOT_CONNECTED:
|
||||
return "REMOTE OFF";
|
||||
case REMOTE_CONNECTED:
|
||||
return "REMOTE ON";
|
||||
case AUTO_SHOOTING_MODE:
|
||||
return "AUTO SHOOT";
|
||||
case IMU_CALIBERATION_MODE:
|
||||
return "IMU CAL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t tft_mode_color(RobotMode_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case NORMAL_MODE:
|
||||
return TFT_COLOR_GREEN;
|
||||
case SYS_ERROR_OCCURRED:
|
||||
case REMOTE_NOT_CONNECTED:
|
||||
return TFT_COLOR_RED;
|
||||
case REMOTE_CONNECTED:
|
||||
return TFT_COLOR_YELLOW;
|
||||
case AUTO_SHOOTING_MODE:
|
||||
return TFT_COLOR_CYAN;
|
||||
case IMU_CALIBERATION_MODE:
|
||||
return TFT_COLOR_MAGENTA;
|
||||
default:
|
||||
return TFT_COLOR_LIGHT_GRAY;
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t tft_temperature_to_tenths(float temperature_c)
|
||||
{
|
||||
return (int16_t) ((temperature_c * 10.0f) + (temperature_c >= 0.0f ? 0.5f : -0.5f));
|
||||
}
|
||||
|
||||
static void tft_format_temperature(char *buf, size_t len, int16_t temperature_tenths)
|
||||
{
|
||||
uint16_t abs_temp;
|
||||
|
||||
if (buf == NULL || len == 0U)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (temperature_tenths < 0)
|
||||
{
|
||||
abs_temp = (uint16_t) (-temperature_tenths);
|
||||
(void) snprintf(buf, len, "-%u.%u C", abs_temp / 10U, abs_temp % 10U);
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_temp = (uint16_t) temperature_tenths;
|
||||
(void) snprintf(buf, len, "%u.%u C", abs_temp / 10U, abs_temp % 10U);
|
||||
}
|
||||
}
|
||||
|
||||
static void tft_draw_status_layout(void)
|
||||
{
|
||||
TFT_Clear(TFT_COLOR_BLACK);
|
||||
TFT_DrawString(16U, 16U, "DM LCD", TFT_COLOR_CYAN, TFT_COLOR_BLACK, 3U);
|
||||
TFT_FillRect(16U, 54U, 248U, 2U, TFT_COLOR_DARK_GRAY);
|
||||
TFT_DrawString(16U, 76U, "TEMP:", TFT_COLOR_YELLOW, TFT_COLOR_BLACK, 2U);
|
||||
TFT_DrawString(16U, 132U, "MODE:", TFT_COLOR_YELLOW, TFT_COLOR_BLACK, 2U);
|
||||
}
|
||||
|
||||
void TFT_ShowStatus(float temperature_c, RobotMode_t mode)
|
||||
{
|
||||
static bool layout_ready = false;
|
||||
static int16_t last_temperature_tenths = INT16_MIN;
|
||||
static RobotMode_t last_mode = (RobotMode_t) 0xFF;
|
||||
int16_t temperature_tenths = tft_temperature_to_tenths(temperature_c);
|
||||
char temperature_text[16];
|
||||
const char *mode_text = TFT_RobotModeText(mode);
|
||||
|
||||
if (!tft_initialized)
|
||||
{
|
||||
TFT_Init();
|
||||
}
|
||||
|
||||
if (!layout_ready)
|
||||
{
|
||||
tft_draw_status_layout();
|
||||
layout_ready = true;
|
||||
}
|
||||
|
||||
if (temperature_tenths != last_temperature_tenths)
|
||||
{
|
||||
uint16_t temperature_color = temperature_tenths >= 550 ? TFT_COLOR_RED : TFT_COLOR_WHITE;
|
||||
tft_format_temperature(temperature_text, sizeof(temperature_text), temperature_tenths);
|
||||
TFT_FillRect(96U, 68U, 168U, 32U, TFT_COLOR_BLACK);
|
||||
TFT_DrawString(100U, 70U, temperature_text, temperature_color, TFT_COLOR_BLACK, 3U);
|
||||
last_temperature_tenths = temperature_tenths;
|
||||
}
|
||||
|
||||
if (mode != last_mode)
|
||||
{
|
||||
TFT_FillRect(96U, 124U, 184U, 32U, TFT_COLOR_BLACK);
|
||||
TFT_DrawString(100U, 126U, mode_text, tft_mode_color(mode), TFT_COLOR_BLACK, 3U);
|
||||
last_mode = mode;
|
||||
}
|
||||
}
|
||||
86
User_Code/module/periph/tft/tft.h
Normal file
86
User_Code/module/periph/tft/tft.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef TFT_H
|
||||
#define TFT_H
|
||||
|
||||
#include "main.h"
|
||||
#include "robot_def.h"
|
||||
#include "spi.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TFT_USE_HORIZONTAL 2U
|
||||
|
||||
#if (TFT_USE_HORIZONTAL == 0U) || (TFT_USE_HORIZONTAL == 1U)
|
||||
#define TFT_LCD_W 240U
|
||||
#define TFT_LCD_H 280U
|
||||
#else
|
||||
#define TFT_LCD_W 280U
|
||||
#define TFT_LCD_H 240U
|
||||
#endif
|
||||
|
||||
#ifndef TFT_SPI_UNIT
|
||||
#define TFT_SPI_UNIT hspi1
|
||||
#endif
|
||||
|
||||
#if defined(LCD_CS_GPIO_Port) && defined(LCD_CS_Pin)
|
||||
#define TFT_CS_GPIO_Port LCD_CS_GPIO_Port
|
||||
#define TFT_CS_Pin LCD_CS_Pin
|
||||
#else
|
||||
#define TFT_CS_GPIO_Port cs2_GPIO_Port
|
||||
#define TFT_CS_Pin cs2_Pin
|
||||
#endif
|
||||
|
||||
#if defined(LCD_BLK_GPIO_Port) && defined(LCD_BLK_Pin)
|
||||
#define TFT_BLK_GPIO_Port LCD_BLK_GPIO_Port
|
||||
#define TFT_BLK_Pin LCD_BLK_Pin
|
||||
#else
|
||||
#define TFT_BLK_GPIO_Port cs1_GPIO_Port
|
||||
#define TFT_BLK_Pin cs1_Pin
|
||||
#endif
|
||||
|
||||
#if defined(LCD_RES_GPIO_Port) && defined(LCD_RES_Pin)
|
||||
#define TFT_RES_GPIO_Port LCD_RES_GPIO_Port
|
||||
#define TFT_RES_Pin LCD_RES_Pin
|
||||
#else
|
||||
#define TFT_RES_GPIO_Port cs4_GPIO_Port
|
||||
#define TFT_RES_Pin cs4_Pin
|
||||
#endif
|
||||
|
||||
#if defined(LCD_DC_GPIO_Port) && defined(LCD_DC_Pin)
|
||||
#define TFT_DC_GPIO_Port LCD_DC_GPIO_Port
|
||||
#define TFT_DC_Pin LCD_DC_Pin
|
||||
#else
|
||||
#define TFT_DC_GPIO_Port cs3_GPIO_Port
|
||||
#define TFT_DC_Pin cs3_Pin
|
||||
#endif
|
||||
|
||||
#define TFT_COLOR_WHITE 0xFFFFU
|
||||
#define TFT_COLOR_BLACK 0x0000U
|
||||
#define TFT_COLOR_BLUE 0x001FU
|
||||
#define TFT_COLOR_RED 0xF800U
|
||||
#define TFT_COLOR_GREEN 0x07E0U
|
||||
#define TFT_COLOR_CYAN 0x7FFFU
|
||||
#define TFT_COLOR_YELLOW 0xFFE0U
|
||||
#define TFT_COLOR_MAGENTA 0xF81FU
|
||||
#define TFT_COLOR_DARK_GRAY 0x4208U
|
||||
#define TFT_COLOR_LIGHT_GRAY 0xC618U
|
||||
|
||||
void TFT_Init(void);
|
||||
void TFT_Clear(uint16_t color);
|
||||
void TFT_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
|
||||
void TFT_DrawPoint(uint16_t x, uint16_t y, uint16_t color);
|
||||
void TFT_DrawString(uint16_t x, uint16_t y, const char *text, uint16_t fc, uint16_t bc, uint8_t scale);
|
||||
void TFT_ShowStatus(float temperature_c, RobotMode_t mode);
|
||||
const char *TFT_RobotModeText(RobotMode_t mode);
|
||||
|
||||
void LCD_Init(void);
|
||||
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
||||
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
366
User_Code/module/periph/w25q64/w25q64.c
Normal file
366
User_Code/module/periph/w25q64/w25q64.c
Normal file
@@ -0,0 +1,366 @@
|
||||
#include "w25q64.h"
|
||||
#include <string.h>
|
||||
|
||||
static W25Q64_Handle_t w25q64 = {0};
|
||||
static bool w25q64_attached = false;
|
||||
static bool w25q64_ready = false;
|
||||
|
||||
static void w25q64_cs_low(void)
|
||||
{
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void w25q64_cs_high(void)
|
||||
{
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_SET);
|
||||
}
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_spi_tx(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!w25q64_attached || w25q64.hspi == NULL)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (HAL_SPI_Transmit(w25q64.hspi, (uint8_t *) data, len, w25q64.timeout_ms) != HAL_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_spi_rx(uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!w25q64_attached || w25q64.hspi == NULL)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (HAL_SPI_Receive(w25q64.hspi, data, len, w25q64.timeout_ms) != HAL_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_write_enable(void)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_WRITE_ENABLE;
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_read_status(uint8_t *status)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_READ_STATUS_1;
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if (w25q64_spi_rx(status, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_wait_ready(uint32_t timeout_ms)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
uint32_t start = HAL_GetTick();
|
||||
|
||||
do
|
||||
{
|
||||
if (w25q64_read_status(&status) != W25Q64_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if ((status & 0x01U) == 0U)
|
||||
{
|
||||
return W25Q64_OK;
|
||||
}
|
||||
} while ((HAL_GetTick() - start) < timeout_ms);
|
||||
|
||||
return W25Q64_ERR_BUSY;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_command_addr(uint8_t cmd, uint32_t addr)
|
||||
{
|
||||
uint8_t header[4] = {
|
||||
cmd,
|
||||
(uint8_t) (addr >> 16),
|
||||
(uint8_t) (addr >> 8),
|
||||
(uint8_t) addr
|
||||
};
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(header, sizeof(header)) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
void W25Q64_Attach(W25Q64_Handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
W25Q64_Detach();
|
||||
return;
|
||||
}
|
||||
|
||||
w25q64 = *handle;
|
||||
w25q64_attached = (w25q64.hspi != NULL) && (w25q64.cs_port != NULL);
|
||||
w25q64.timeout_ms = (w25q64.timeout_ms == 0U) ? 100U : w25q64.timeout_ms;
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_SET);
|
||||
}
|
||||
w25q64_ready = false;
|
||||
}
|
||||
|
||||
void W25Q64_Detach(void)
|
||||
{
|
||||
memset(&w25q64, 0, sizeof(w25q64));
|
||||
w25q64_attached = false;
|
||||
w25q64_ready = false;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_ReadID(uint32_t *jedec_id)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_READ_ID;
|
||||
uint8_t id[3] = {0};
|
||||
|
||||
if (jedec_id == NULL)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_attached)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if (w25q64_spi_rx(id, 3U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
*jedec_id = ((uint32_t) id[0] << 16) | ((uint32_t) id[1] << 8) | id[2];
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Init(void)
|
||||
{
|
||||
uint32_t jedec_id = 0;
|
||||
|
||||
if (!w25q64_attached)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (W25Q64_ReadID(&jedec_id) != W25Q64_OK)
|
||||
{
|
||||
w25q64_ready = false;
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
|
||||
w25q64_ready = (jedec_id == W25Q64_JEDEC_ID);
|
||||
return w25q64_ready ? W25Q64_OK : W25Q64_ERR_ID;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Read(uint32_t addr, uint8_t *data, uint32_t len)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
uint32_t offset = 0U;
|
||||
|
||||
if (data == NULL || len == 0U)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_READ_DATA, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (offset < len)
|
||||
{
|
||||
uint16_t chunk = (uint16_t) ((len - offset) > UINT16_MAX ? UINT16_MAX : (len - offset));
|
||||
ret = w25q64_spi_rx(data + offset, chunk);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return ret;
|
||||
}
|
||||
offset += chunk;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_page_program(uint32_t addr, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_PAGE_PROGRAM, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (w25q64_spi_tx(data, len) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(w25q64.timeout_ms);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Write(uint32_t addr, const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t offset = 0U;
|
||||
|
||||
if (data == NULL || len == 0U)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
while (offset < len)
|
||||
{
|
||||
uint32_t page_offset = (addr + offset) % W25Q64_PAGE_SIZE;
|
||||
uint32_t room = W25Q64_PAGE_SIZE - page_offset;
|
||||
uint16_t chunk = (uint16_t) ((len - offset) < room ? (len - offset) : room);
|
||||
W25Q64_Status_t ret = w25q64_page_program(addr + offset, data + offset, chunk);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
offset += chunk;
|
||||
}
|
||||
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_EraseSector(uint32_t addr)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_SECTOR_ERASE, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(400U);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Erase64K(uint32_t addr)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_BLOCK_ERASE_64K, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(2000U);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_ChipErase(void)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_CHIP_ERASE;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (w25q64_write_enable() != W25Q64_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(100000U);
|
||||
}
|
||||
59
User_Code/module/periph/w25q64/w25q64.h
Normal file
59
User_Code/module/periph/w25q64/w25q64.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef W25Q64_H
|
||||
#define W25Q64_H
|
||||
|
||||
#include "main.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define W25Q64_PAGE_SIZE 256U
|
||||
#define W25Q64_SECTOR_SIZE 4096U
|
||||
#define W25Q64_FLASH_SIZE 0x800000U
|
||||
#define W25Q64_JEDEC_ID 0xEF4017U
|
||||
|
||||
#define W25Q64_CMD_WRITE_ENABLE 0x06U
|
||||
#define W25Q64_CMD_READ_STATUS_1 0x05U
|
||||
#define W25Q64_CMD_READ_ID 0x9FU
|
||||
#define W25Q64_CMD_READ_DATA 0x03U
|
||||
#define W25Q64_CMD_PAGE_PROGRAM 0x02U
|
||||
#define W25Q64_CMD_SECTOR_ERASE 0x20U
|
||||
#define W25Q64_CMD_BLOCK_ERASE_64K 0xD8U
|
||||
#define W25Q64_CMD_CHIP_ERASE 0xC7U
|
||||
|
||||
typedef enum
|
||||
{
|
||||
W25Q64_OK = 0,
|
||||
W25Q64_ERR_PARAM = -1,
|
||||
W25Q64_ERR_NOT_ATTACHED = -2,
|
||||
W25Q64_ERR_HAL = -3,
|
||||
W25Q64_ERR_ID = -4,
|
||||
W25Q64_ERR_BUSY = -5
|
||||
} W25Q64_Status_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SPI_HandleTypeDef *hspi;
|
||||
GPIO_TypeDef *cs_port;
|
||||
uint16_t cs_pin;
|
||||
uint32_t timeout_ms;
|
||||
} W25Q64_Handle_t;
|
||||
|
||||
void W25Q64_Attach(W25Q64_Handle_t *handle);
|
||||
void W25Q64_Detach(void);
|
||||
|
||||
W25Q64_Status_t W25Q64_Init(void);
|
||||
W25Q64_Status_t W25Q64_ReadID(uint32_t *jedec_id);
|
||||
W25Q64_Status_t W25Q64_Read(uint32_t addr, uint8_t *data, uint32_t len);
|
||||
W25Q64_Status_t W25Q64_Write(uint32_t addr, const uint8_t *data, uint32_t len);
|
||||
W25Q64_Status_t W25Q64_EraseSector(uint32_t addr);
|
||||
W25Q64_Status_t W25Q64_Erase64K(uint32_t addr);
|
||||
W25Q64_Status_t W25Q64_ChipErase(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
BIN
tmp/pdfs/dm_manual.pdf
Normal file
BIN
tmp/pdfs/dm_manual.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user