aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--boards/base/STM32F746-Discovery/board.mk8
-rw-r--r--boards/base/STM32F746-Discovery/board_STM32LTDC.h2
-rw-r--r--boards/base/STM32F746-Discovery/example_raw32/Makefile2
-rw-r--r--boards/base/STM32F746-Discovery/gmouse_lld_FT5336_board.h76
-rw-r--r--boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c4
-rw-r--r--boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c48
-rw-r--r--boards/base/STM32F746-Discovery/stm32f7_i2c.c164
-rw-r--r--boards/base/STM32F746-Discovery/stm32f7_i2c.h14
-rw-r--r--boards/base/Win32/board.mk4
-rw-r--r--drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c96
-rw-r--r--drivers/ginput/touch/FT5336/driver.mk2
-rw-r--r--drivers/ginput/touch/FT5336/ft5336.h241
-rw-r--r--drivers/ginput/touch/FT5336/gmouse_lld_FT5336.c106
-rw-r--r--drivers/ginput/touch/FT5336/gmouse_lld_FT5336_board_template.h59
-rw-r--r--gfxconf.example.h4
-rw-r--r--src/gos/gos.mk4
-rw-r--r--src/gos/gos_arduino.c492
-rw-r--r--src/gos/gos_arduino.h64
-rw-r--r--src/gos/gos_chibios.c2
-rw-r--r--src/gos/gos_ecos.c3
-rw-r--r--src/gos/gos_freertos.c3
-rw-r--r--src/gos/gos_mk.c2
-rw-r--r--src/gos/gos_options.h42
-rw-r--r--src/gos/gos_raw32.c663
-rw-r--r--src/gos/gos_raw32.h77
-rw-r--r--src/gos/gos_rawrtos.c3
-rw-r--r--src/gos/gos_x_heap.c195
-rw-r--r--src/gos/gos_x_heap.h62
-rw-r--r--src/gos/gos_x_threads.c672
-rw-r--r--src/gos/gos_x_threads.h103
30 files changed, 1906 insertions, 1311 deletions
diff --git a/boards/base/STM32F746-Discovery/board.mk b/boards/base/STM32F746-Discovery/board.mk
index dd1f8441..9386fae0 100644
--- a/boards/base/STM32F746-Discovery/board.mk
+++ b/boards/base/STM32F746-Discovery/board.mk
@@ -18,8 +18,9 @@ ifeq ($(OPT_OS),raw32)
GFXSRC += $(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_startup.s \
$(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c \
$(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c \
- $(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_interrupts.c
- GFXDEFS += GFX_OS_EXTRA_INIT_FUNCTION=Raw32OSInit
+ $(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_interrupts.c \
+ $(GFXLIB)/boards/base/STM32F746-Discovery/stm32f7_i2c.c
+ GFXDEFS += GFX_OS_EXTRA_INIT_FUNCTION=Raw32OSInit GFX_OS_INIT_NO_WARNING=TRUE
SRCFLAGS+= -std=c99
GFXINC += $(CMSIS)/Device/ST/STM32F7xx/Include \
$(CMSIS)/Include \
@@ -27,4 +28,5 @@ ifeq ($(OPT_OS),raw32)
LDSCRIPT = $(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746nghx_flash.ld
endif
-include $(GFXLIB)/drivers/gdisp/STM32LTDC/driver.mk \ No newline at end of file
+include $(GFXLIB)/drivers/gdisp/STM32LTDC/driver.mk
+include $(GFXLIB)/drivers/ginput/touch/FT5336/driver.mk \ No newline at end of file
diff --git a/boards/base/STM32F746-Discovery/board_STM32LTDC.h b/boards/base/STM32F746-Discovery/board_STM32LTDC.h
index 059e7e9d..ffe28e02 100644
--- a/boards/base/STM32F746-Discovery/board_STM32LTDC.h
+++ b/boards/base/STM32F746-Discovery/board_STM32LTDC.h
@@ -44,8 +44,6 @@ static const ltdcConfig driverCfg = {
static void configureLcdPins(void)
{
- GPIO_InitTypeDef gpio_init_structure;
-
// Enable GPIOs clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN; // GPIOE
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOGEN; // GPIOG
diff --git a/boards/base/STM32F746-Discovery/example_raw32/Makefile b/boards/base/STM32F746-Discovery/example_raw32/Makefile
index 298d74bf..dee0f01a 100644
--- a/boards/base/STM32F746-Discovery/example_raw32/Makefile
+++ b/boards/base/STM32F746-Discovery/example_raw32/Makefile
@@ -55,7 +55,7 @@ LDFLAGS =
SRC =
OBJS =
-DEFS = GOS_RAW_HEAP_SIZE=40960
+DEFS = GFX_OS_HEAP_SIZE=40960
LIBS =
INCPATH =
diff --git a/boards/base/STM32F746-Discovery/gmouse_lld_FT5336_board.h b/boards/base/STM32F746-Discovery/gmouse_lld_FT5336_board.h
new file mode 100644
index 00000000..8031eca5
--- /dev/null
+++ b/boards/base/STM32F746-Discovery/gmouse_lld_FT5336_board.h
@@ -0,0 +1,76 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef _GINPUT_LLD_MOUSE_BOARD_H
+#define _GINPUT_LLD_MOUSE_BOARD_H
+
+#include "stm32f7xx.h"
+#include "stm32f7_i2c.h"
+
+// Resolution and Accuracy Settings
+#define GMOUSE_FT5336_PEN_CALIBRATE_ERROR 8
+#define GMOUSE_FT5336_PEN_CLICK_ERROR 6
+#define GMOUSE_FT5336_PEN_MOVE_ERROR 4
+#define GMOUSE_FT5336_FINGER_CALIBRATE_ERROR 14
+#define GMOUSE_FT5336_FINGER_CLICK_ERROR 18
+#define GMOUSE_FT5336_FINGER_MOVE_ERROR 14
+
+// How much extra data to allocate at the end of the GMouse structure for the board's use
+#define GMOUSE_FT5336_BOARD_DATA_SIZE 0
+
+// The FT5336 I2C slave address (including the R/W bit)
+#define FT5336_SLAVE_ADDR 0x70
+
+static bool_t init_board(GMouse* m, unsigned instance)
+{
+ (void)m;
+ (void)instance;
+
+ // I2C3_SCL GPIOH7, alternate, opendrain, highspeed
+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN; // Enable clock for
+ GPIOH->MODER |= GPIO_MODER_MODER7_1; // Alternate function
+ GPIOH->OTYPER |= GPIO_OTYPER_OT_7; // OpenDrain
+ GPIOH->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR7; // LowSpeed
+ GPIOH->AFR[0] |= (0b0100 << 4*7); // AF4
+
+ // I2C3_SDA GPIOH8, alternate, opendrain, highspeed
+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN; // Enable clock
+ GPIOH->MODER |= GPIO_MODER_MODER8_1; // Alternate function
+ GPIOH->OTYPER |= GPIO_OTYPER_OT_8; // OpenDrain
+ GPIOH->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR8; // LowSpeed
+ GPIOH->AFR[1] |= (0b0100 << 4*0); // AF4
+
+ // Initialize the I2C3 peripheral
+ if (!(i2cInit(I2C3))) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void write_reg(GMouse* m, uint8_t reg, uint8_t val)
+{
+ (void)m;
+
+ i2cWriteReg(I2C3, FT5336_SLAVE_ADDR, reg, val);
+}
+
+static uint8_t read_byte(GMouse* m, uint8_t reg)
+{
+ (void)m;
+
+ return i2cReadByte(I2C3, FT5336_SLAVE_ADDR, reg);
+}
+
+static uint16_t read_word(GMouse* m, uint8_t reg)
+{
+ (void)m;
+
+ return i2cReadWord(I2C3, FT5336_SLAVE_ADDR, reg);
+}
+
+#endif /* _GINPUT_LLD_MOUSE_BOARD_H */
diff --git a/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c b/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c
index 9ffe25ee..f7c4952d 100644
--- a/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c
+++ b/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c
@@ -176,7 +176,9 @@ void SystemInit(void)
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
- RCC->PLLCFGR = 0x24003010;
+ //RCC->PLLCFGR = 0x24003010; // From discovery example
+ // M = 12 = 0b1100, N = 192 = 0b11000000, P = 2 = 0b10, Q = 2 = 0b10
+ RCC->PLLCFGR = 0x00C0980C;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
diff --git a/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c b/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
index 3d493e5c..794d3c66 100644
--- a/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
+++ b/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
@@ -13,7 +13,6 @@ systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
static void SystemClock_Config(void);
static void CPU_CACHE_Enable(void);
-static void LCD_Config(void);
void Raw32OSInit(void) {
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
@@ -65,6 +64,7 @@ void Raw32OSInit(void) {
*/
void SystemClock_Config(void)
{
+#if 0
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
HAL_StatusTypeDef ret = HAL_OK;
@@ -74,10 +74,10 @@ void SystemClock_Config(void)
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 25;
- RCC_OscInitStruct.PLL.PLLN = 400; // 432
+ RCC_OscInitStruct.PLL.PLLM = 12;
+ RCC_OscInitStruct.PLL.PLLN = 192; // 432
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
- RCC_OscInitStruct.PLL.PLLQ = 8; // 9
+ RCC_OscInitStruct.PLL.PLLQ = 2; // 9
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret != HAL_OK)
@@ -104,6 +104,46 @@ void SystemClock_Config(void)
{
while(1) { ; }
}
+#else
+
+ RCC_OscInitTypeDef RCC_OscInitStruct;
+ RCC_ClkInitTypeDef RCC_ClkInitStruct;
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
+
+ __PWR_CLK_ENABLE();
+
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+ RCC_OscInitStruct.HSICalibrationValue = 16;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLM = 12;
+ RCC_OscInitStruct.PLL.PLLN = 192;
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
+ RCC_OscInitStruct.PLL.PLLQ = 2;
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ HAL_PWREx_ActivateOverDrive();
+
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+ |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
+
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
+ PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
+
+ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
+
+ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
+#endif
}
/**
diff --git a/boards/base/STM32F746-Discovery/stm32f7_i2c.c b/boards/base/STM32F746-Discovery/stm32f7_i2c.c
new file mode 100644
index 00000000..b0fa8163
--- /dev/null
+++ b/boards/base/STM32F746-Discovery/stm32f7_i2c.c
@@ -0,0 +1,164 @@
+#include "stm32f7_i2c.h"
+
+/*
+ * The CR2 register needs atomic access. Hence always use this function to setup a transfer configuration.
+ */
+static void _i2cConfigTransfer(I2C_TypeDef* i2c, uint16_t slaveAddr, uint8_t numBytes, uint32_t mode, uint32_t request)
+{
+ uint32_t tmpreg = 0;
+
+ // Get the current CR2 register value
+ tmpreg = i2c->CR2;
+
+ // Clear tmpreg specific bits
+ tmpreg &= (uint32_t) ~((uint32_t) (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));
+
+ // update tmpreg
+ tmpreg |= (uint32_t) (((uint32_t) slaveAddr & I2C_CR2_SADD) | (((uint32_t) numBytes << 16) & I2C_CR2_NBYTES) | (uint32_t) mode | (uint32_t) request);
+
+ // Update the actual CR2 contents
+ i2c->CR2 = tmpreg;
+}
+
+/*
+ * According to the STM32Cube HAL the CR2 register needs to be reset after each transaction.
+ */
+static void _i2cResetCr2(I2C_TypeDef* i2c)
+{
+ i2c->CR2 &= (uint32_t) ~((uint32_t) (I2C_CR2_SADD | I2C_CR2_HEAD10R | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_RD_WRN));
+}
+
+bool_t i2cInit(I2C_TypeDef* i2c)
+{
+ // Enable I2Cx peripheral clock.
+ // Select APB1 as clock source
+ if (i2c == I2C1) {
+ RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C1SEL;
+ RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
+ } else if (i2c == I2C2) {
+ RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C2SEL;
+ RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
+ } else if (i2c == I2C3) {
+ RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C3SEL;
+ RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;
+ } else if (i2c == I2C4) {
+ RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_I2C4SEL;
+ RCC->APB1ENR |= RCC_APB1ENR_I2C4EN;
+ } else {
+ return FALSE;
+ }
+
+ // Disable the I2Cx peripheral
+ i2c->CR1 &= ~I2C_CR1_PE;
+ while (i2c->CR1 & I2C_CR1_PE);
+
+ // Set timings. Asuming I2CCLK is 50 MHz (APB1 clock source)
+ i2c->TIMINGR = 0x40912732; // Discovery BSP code from ST examples
+
+ // Use 7-bit addresses
+ i2c->CR2 &=~ I2C_CR2_ADD10;
+
+ // Enable auto-end mode
+ i2c->CR2 |= I2C_CR2_AUTOEND;
+
+ // Disable the analog filter
+ i2c->CR1 |= I2C_CR1_ANFOFF;
+
+ // Disable NOSTRETCH
+ i2c->CR1 |= I2C_CR1_NOSTRETCH;
+
+ // Enable the I2Cx peripheral
+ i2c->CR1 |= I2C_CR1_PE;
+
+ return TRUE;
+}
+
+void i2cSend(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t length)
+{
+ // We are currently not able to send more than 255 bytes at once
+ if (length > 255) {
+ return;
+ }
+
+ // Setup the configuration
+ _i2cConfigTransfer(i2c, slaveAddr, length, (!I2C_CR2_RD_WRN) | I2C_CR2_AUTOEND, I2C_CR2_START);
+
+ // Transmit the whole buffer
+ while (length > 0) {
+ while (!(i2c->ISR & I2C_ISR_TXIS));
+ i2c->TXDR = *data++;
+ length--;
+ }
+
+ // Wait until the transfer is complete
+ while (!(i2c->ISR & I2C_ISR_TXE));
+
+ // Wait until the stop condition was automagically sent
+ while (!(i2c->ISR & I2C_ISR_STOPF));
+
+ // Reset the STOP bit
+ i2c->ISR &= ~I2C_ISR_STOPF;
+
+ // Reset the CR2 register
+ _i2cResetCr2(i2c);
+}
+
+void i2cSendByte(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t data)
+{
+ i2cSend(i2c, slaveAddr, &data, 1);
+}
+
+void i2cWriteReg(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr, uint8_t value)
+{
+ uint8_t txbuf[2];
+ txbuf[0] = regAddr;
+ txbuf[1] = value;
+
+ i2cSend(i2c, slaveAddr, txbuf, 2);
+}
+
+void i2cRead(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t length)
+{
+ // We are currently not able to read more than 255 bytes at once
+ if (length > 255) {
+ return;
+ }
+
+ // Setup the configuration
+ _i2cConfigTransfer(i2c, slaveAddr, length, I2C_CR2_RD_WRN | I2C_CR2_AUTOEND, I2C_CR2_START);
+
+ // Transmit the whole buffer
+ for (int i = 0; i < length; i++) {
+ while (!(i2c->ISR & I2C_ISR_RXNE));
+ data[i] = i2c->RXDR;
+ }
+
+ // Wait until the stop condition was automagically sent
+ while (!(i2c->ISR & I2C_ISR_STOPF));
+
+ // Reset the STOP bit
+ i2c->ISR &= ~I2C_ISR_STOPF;
+
+ // Reset the CR2 register
+ _i2cResetCr2(i2c);
+}
+
+uint8_t i2cReadByte(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr)
+{
+ uint8_t ret = 0xAA;
+
+ i2cSend(i2c, slaveAddr, &regAddr, 1);
+ i2cRead(i2c, slaveAddr, &ret, 1);
+
+ return ret;
+}
+
+uint16_t i2cReadWord(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr)
+{
+ uint8_t ret[2] = { 0xAA, 0xAA };
+
+ i2cSend(i2c, slaveAddr, &regAddr, 1);
+ i2cRead(i2c, slaveAddr, ret, 2);
+
+ return (uint16_t)((ret[0] << 8) | (ret[1] & 0x00FF));
+}
diff --git a/boards/base/STM32F746-Discovery/stm32f7_i2c.h b/boards/base/STM32F746-Discovery/stm32f7_i2c.h
new file mode 100644
index 00000000..625aeed8
--- /dev/null
+++ b/boards/base/STM32F746-Discovery/stm32f7_i2c.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "stm32f7xx.h"
+#include "gfx.h"
+
+bool_t i2cInit(I2C_TypeDef* i2c);
+
+void i2cSend(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t length);
+void i2cSendByte(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t data);
+void i2cWriteReg(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr, uint8_t value);
+
+void i2cRead(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t* data, uint16_t length);
+uint8_t i2cReadByte(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr);
+uint16_t i2cReadWord(I2C_TypeDef* i2c, uint8_t slaveAddr, uint8_t regAddr);
diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk
index adcbaeaf..b4577927 100644
--- a/boards/base/Win32/board.mk
+++ b/boards/base/Win32/board.mk
@@ -3,3 +3,7 @@ GFXSRC +=
GFXLIBS +=
include $(GFXLIB)/drivers/multiple/Win32/driver.mk
include $(GFXLIB)/drivers/gaudio/Win32/driver.mk
+
+ifeq ($(OPT_OS),win32.raw32)
+ GFXDEFS += GFX_OS_INIT_NO_WARNING=TRUE
+endif
diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
index ba656eb0..9c2de092 100644
--- a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
+++ b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
@@ -34,7 +34,7 @@
typedef struct ltdcLayerConfig {
// Frame
- LLDCOLOR_TYPE *frame; // Frame buffer address
+ LLDCOLOR_TYPE* frame; // Frame buffer address
coord_t width, height; // Frame size in pixels
coord_t pitch; // Line pitch, in bytes
uint16_t fmt; // Pixel format in LTDC format
@@ -102,7 +102,7 @@ typedef struct ltdcConfig {
/* Driver exported functions. */
/*===========================================================================*/
-static void LTDC_Reload(void)
+static void _ltdc_reload(void)
{
LTDC->SRCR |= LTDC_SRCR_IMR;
@@ -111,7 +111,7 @@ static void LTDC_Reload(void)
}
}
-static void LTDC_LayerInit(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg)
+static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg)
{
static const uint8_t fmt2Bpp[] = {
4, /* LTDC_FMT_ARGB8888 */
@@ -144,15 +144,14 @@ static void LTDC_LayerInit(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* p
pLayReg->CKCR = (pLayReg->CKCR & ~0x00FFFFFF) | (pCfg->keycolor & 0x00FFFFFF);
pLayReg->CACR = (pLayReg->CACR & ~LTDC_LxCACR_CONSTA) | ((uint32_t)pCfg->alpha & LTDC_LxCACR_CONSTA);
pLayReg->BFCR = (pLayReg->BFCR & ~(LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)) | ((uint32_t)pCfg->blending & (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2));
- for (start = 0; start < pCfg->palettelen; start++) {
+ for (start = 0; start < pCfg->palettelen; start++)
pLayReg->CLUTWR = ((uint32_t)start << 24) | (pCfg->palette[start] & 0x00FFFFFF);
- }
// Final flags
pLayReg->CR = (pLayReg->CR & ~LTDC_LEF_MASK) | ((uint32_t)pCfg->layerflags & LTDC_LEF_MASK);
}
-static void LTDC_Init(void)
+static void _ltdc_init(void)
{
// Set up the display scanning
uint32_t hacc, vacc;
@@ -176,7 +175,7 @@ static void LTDC_Init(void)
// Turn off the controller and its interrupts
LTDC->GCR = 0;
LTDC->IER = 0;
- LTDC_Reload();
+ _ltdc_reload();
// Set synchronization params
hacc = driverCfg.hsync - 1;
@@ -205,21 +204,19 @@ static void LTDC_Init(void)
LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (driverCfg.bgcolor & 0x00FFFFFF);
// Load the background layer
- LTDC_LayerInit(LTDC_Layer1, &driverCfg.bglayer);
+ _ltdc_layer_init(LTDC_Layer1, &driverCfg.bglayer);
// Load the foreground layer
- LTDC_LayerInit(LTDC_Layer2, &driverCfg.fglayer);
+ _ltdc_layer_init(LTDC_Layer2, &driverCfg.fglayer);
// Interrupt handling
- //nvicEnableVector(STM32_LTDC_EV_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_EV_IRQ_PRIORITY));
- //nvicEnableVector(STM32_LTDC_ER_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_ER_IRQ_PRIORITY));
// Possible flags - LTDC_IER_RRIE, LTDC_IER_LIE, LTDC_IER_FUIE, LTDC_IER_TERRIE etc
LTDC->IER = 0;
// Set everything going
- LTDC_Reload();
+ _ltdc_reload();
LTDC->GCR |= LTDC_GCR_LTDCEN;
- LTDC_Reload();
+ _ltdc_reload();
}
LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
@@ -232,7 +229,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
init_board(g);
// Initialise the LTDC controller
- LTDC_Init();
+ _ltdc_init();
// Initialise DMA2D
#if LTDC_USE_DMA2D
@@ -318,21 +315,25 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
{
switch(g->p.x) {
case GDISP_CONTROL_POWER:
- if (g->g.Powermode == (powermode_t)g->p.ptr)
+ // Don't do anything if it is the same power mode
+ if (g->g.Powermode == (powermode_t)g->p.ptr) {
return;
+ }
+
switch((powermode_t)g->p.ptr) {
- case powerOff: case powerOn: case powerSleep: case powerDeepSleep:
- // TODO
- break;
default:
return;
}
+
g->g.Powermode = (powermode_t)g->p.ptr;
return;
case GDISP_CONTROL_ORIENTATION:
- if (g->g.Orientation == (orientation_t)g->p.ptr)
+ // Don't do anything if it is the same power mode
+ if (g->g.Orientation == (orientation_t)g->p.ptr) {
return;
+ }
+
switch((orientation_t)g->p.ptr) {
case GDISP_ROTATE_0:
case GDISP_ROTATE_180:
@@ -357,6 +358,7 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
default:
return;
}
+
g->g.Orientation = (orientation_t)g->p.ptr;
return;
@@ -398,32 +400,60 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
// Uses p.x,p.y p.cx,p.cy p.color
LLDSPEC void gdisp_lld_fill_area(GDisplay* g)
- {
- LLDCOLOR_TYPE c;
-
+ {
+ uint32_t reg_omar = 0;
+ uint32_t reg_oor = 0;
+ uint32_t reg_nlr = 0;
+
// Wait until DMA2D is ready
while (1) {
if (!(DMA2D->CR & DMA2D_CR_START)) {
break;
}
}
-
- c = gdispColor2Native(g->p.color);
-
- // Output color register
- DMA2D->OCOLR = (uint32_t)c;
-
+
+ // Calculate pixel positions and stuff like that
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ default:
+ reg_omar = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
+ reg_oor = g->g.Width - g->p.cx;
+ reg_nlr = (g->p.cx << 16) | (g->p.cy);
+ break;
+
+ case GDISP_ROTATE_90:
+ break;
+
+ case GDISP_ROTATE_180:
+ reg_omar = g->g.Width * (g->g.Height - g->p.y - g->p.cy) * LTDC_PIXELBYTES + (g->g.Width - g->p.x - g->p.cx) * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
+ reg_oor = g->g.Width - g->p.cx;
+ reg_nlr = (g->p.cy << 16) | (g->p.cx);
+ break;
+
+ case GDISP_ROTATE_270:
+ break;
+ }
+ #else
+ reg_omar = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
+ reg_oor = g->g.Width - g->p.cx;
+ reg_nlr = (g->p.cx << 16) | (g->p.cy);
+ #endif
+
// Output memory address register
- DMA2D->OMAR = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
+ DMA2D->OMAR = reg_omar;
// Output offset register (in pixels)
- DMA2D->OOR = g->g.Width - g->p.cx;
-
+ DMA2D->OOR = reg_oor;
+
// PL (pixel per lines to be transferred); NL (number of lines)
- DMA2D->NLR = (g->p.cx << 16) | (g->p.cy);
+ DMA2D->NLR = reg_nlr;
+
+ // Output color register
+ DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color));
// Set MODE to R2M and Start the process
- DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START;
+ DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START;
}
// Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer)
diff --git a/drivers/ginput/touch/FT5336/driver.mk b/drivers/ginput/touch/FT5336/driver.mk
new file mode 100644
index 00000000..be3cab6e
--- /dev/null
+++ b/drivers/ginput/touch/FT5336/driver.mk
@@ -0,0 +1,2 @@
+# List the required driver.
+GFXSRC += $(GFXLIB)/drivers/ginput/touch/FT5336/gmouse_lld_FT5336.c
diff --git a/drivers/ginput/touch/FT5336/ft5336.h b/drivers/ginput/touch/FT5336/ft5336.h
new file mode 100644
index 00000000..4940cc42
--- /dev/null
+++ b/drivers/ginput/touch/FT5336/ft5336.h
@@ -0,0 +1,241 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef _FT5336_H
+#define _FT5336_H
+
+// I2C Slave address of touchscreen FocalTech FT5336
+#define FT5336_I2C_SLAVE_ADDRESS 0x70
+
+// Maximum border values of the touchscreen pad
+#define FT5336_MAX_WIDTH 480 // Touchscreen pad max width
+#define FT5336_MAX_HEIGHT 272 // Touchscreen pad max height
+
+// Possible values of driver functions return status
+#define FT5336_STATUS_OK 0x00
+#define FT5336_STATUS_NOT_OK 0x01
+
+// Possible values of global variable 'TS_I2C_Initialized'
+#define FT5336_I2C_NOT_INITIALIZED 0x00
+#define FT5336_I2C_INITIALIZED 0x01
+
+// Max detectable simultaneous touches
+#define FT5336_MAX_DETECTABLE_TOUCH 0x05
+
+// Current mode register of the FT5336 (R)/W
+#define FT5336_DEV_MODE_REG 0x00
+
+// Possible values of FT5336_DEV_MODE_REG
+#define FT5336_DEV_MODE_WORKING 0x00
+#define FT5336_DEV_MODE_FACTORY 0x04
+
+#define FT5336_DEV_MODE_MASK 0x07
+#define FT5336_DEV_MODE_SHIFT 0x04
+
+// Gesture ID register
+#define FT5336_GEST_ID_REG 0x01
+
+// Possible values of FT5336_GEST_ID_REG
+#define FT5336_GEST_ID_NO_GESTURE 0x00
+#define FT5336_GEST_ID_MOVE_UP 0x10
+#define FT5336_GEST_ID_MOVE_RIGHT 0x14
+#define FT5336_GEST_ID_MOVE_DOWN 0x18
+#define FT5336_GEST_ID_MOVE_LEFT 0x1C
+#define FT5336_GEST_ID_SINGLE_CLICK 0x20
+#define FT5336_GEST_ID_DOUBLE_CLICK 0x22
+#define FT5336_GEST_ID_ROTATE_CLOCKWISE 0x28
+#define FT5336_GEST_ID_ROTATE_C_CLOCKWISE 0x29
+#define FT5336_GEST_ID_ZOOM_IN 0x40
+#define FT5336_GEST_ID_ZOOM_OUT 0x49
+
+// Touch Data Status register : gives number of active touch points (0..5)
+#define FT5336_TD_STAT_REG 0x02
+
+// Values related to FT5336_TD_STAT_REG
+#define FT5336_TD_STAT_MASK 0x0F
+#define FT5336_TD_STAT_SHIFT 0x00
+
+// Values Pn_XH and Pn_YH related
+#define FT5336_TOUCH_EVT_FLAG_PRESS_DOWN 0x00
+#define FT5336_TOUCH_EVT_FLAG_LIFT_UP 0x01
+#define FT5336_TOUCH_EVT_FLAG_CONTACT 0x02
+#define FT5336_TOUCH_EVT_FLAG_NO_EVENT 0x03
+
+#define FT5336_TOUCH_EVT_FLAG_SHIFT 0x06
+#define FT5336_TOUCH_EVT_FLAG_MASK (3 << FT5336_TOUCH_EVT_FLAG_SHIFT)
+
+#define FT5336_TOUCH_POS_MSB_MASK 0x0F
+#define FT5336_TOUCH_POS_MSB_SHIFT 0x00
+
+// Values Pn_XL and Pn_YL related
+#define FT5336_TOUCH_POS_LSB_MASK 0xFF
+#define FT5336_TOUCH_POS_LSB_SHIFT 0x00
+
+// Values Pn_WEIGHT related
+#define FT5336_TOUCH_WEIGHT_MASK 0xFF
+#define FT5336_TOUCH_WEIGHT_SHIFT 0x00
+
+// Values related to FT5336_Pn_MISC_REG
+#define FT5336_TOUCH_AREA_MASK (0x04 << 4)
+#define FT5336_TOUCH_AREA_SHIFT 0x04
+
+#define FT5336_P1_XH_REG 0x03
+#define FT5336_P1_XL_REG 0x04
+#define FT5336_P1_YH_REG 0x05
+#define FT5336_P1_YL_REG 0x06
+#define FT5336_P1_WEIGHT_REG 0x07
+#define FT5336_P1_MISC_REG 0x08
+
+#define FT5336_P2_XH_REG 0x09
+#define FT5336_P2_XL_REG 0x0A
+#define FT5336_P2_YH_REG 0x0B
+#define FT5336_P2_YL_REG 0x0C
+#define FT5336_P2_WEIGHT_REG 0x0D
+#define FT5336_P2_MISC_REG 0x0E
+
+#define FT5336_P3_XH_REG 0x0F
+#define FT5336_P3_XL_REG 0x10
+#define FT5336_P3_YH_REG 0x11
+#define FT5336_P3_YL_REG 0x12
+#define FT5336_P3_WEIGHT_REG 0x13
+#define FT5336_P3_MISC_REG 0x14
+
+#define FT5336_P4_XH_REG 0x15
+#define FT5336_P4_XL_REG 0x16
+#define FT5336_P4_YH_REG 0x17
+#define FT5336_P4_YL_REG 0x18
+#define FT5336_P4_WEIGHT_REG 0x19
+#define FT5336_P4_MISC_REG 0x1A
+
+#define FT5336_P5_XH_REG 0x1B
+#define FT5336_P5_XL_REG 0x1C
+#define FT5336_P5_YH_REG 0x1D
+#define FT5336_P5_YL_REG 0x1E
+#define FT5336_P5_WEIGHT_REG 0x1F
+#define FT5336_P5_MISC_REG 0x20
+
+#define FT5336_P6_XH_REG 0x21
+#define FT5336_P6_XL_REG 0x22
+#define FT5336_P6_YH_REG 0x23
+#define FT5336_P6_YL_REG 0x24
+#define FT5336_P6_WEIGHT_REG 0x25
+#define FT5336_P6_MISC_REG 0x26
+
+#define FT5336_P7_XH_REG 0x27
+#define FT5336_P7_XL_REG 0x28
+#define FT5336_P7_YH_REG 0x29
+#define FT5336_P7_YL_REG 0x2A
+#define FT5336_P7_WEIGHT_REG 0x2B
+#define FT5336_P7_MISC_REG 0x2C
+
+#define FT5336_P8_XH_REG 0x2D
+#define FT5336_P8_XL_REG 0x2E
+#define FT5336_P8_YH_REG 0x2F
+#define FT5336_P8_YL_REG 0x30
+#define FT5336_P8_WEIGHT_REG 0x31
+#define FT5336_P8_MISC_REG 0x32
+
+#define FT5336_P9_XH_REG 0x33
+#define FT5336_P9_XL_REG 0x34
+#define FT5336_P9_YH_REG 0x35
+#define FT5336_P9_YL_REG 0x36
+#define FT5336_P9_WEIGHT_REG 0x37
+#define FT5336_P9_MISC_REG 0x38
+
+#define FT5336_P10_XH_REG 0x39
+#define FT5336_P10_XL_REG 0x3A
+#define FT5336_P10_YH_REG 0x3B
+#define FT5336_P10_YL_REG 0x3C
+#define FT5336_P10_WEIGHT_REG 0x3D
+#define FT5336_P10_MISC_REG 0x3E
+
+// Threshold for touch detection
+#define FT5336_TH_GROUP_REG 0x80
+
+// Values FT5336_TH_GROUP_REG : threshold related
+#define FT5336_THRESHOLD_MASK 0xFF
+#define FT5336_THRESHOLD_SHIFT 0x00
+
+// Filter function coefficients
+#define FT5336_TH_DIFF_REG 0x85
+
+// Control register
+#define FT5336_CTRL_REG 0x86
+
+// Values related to FT5336_CTRL_REG
+
+// Will keep the Active mode when there is no touching
+#define FT5336_CTRL_KEEP_ACTIVE_MODE 0x00
+
+// Switching from Active mode to Monitor mode automatically when there is no touching
+#define FT5336_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE 0x01
+
+// The time period of switching from Active mode to Monitor mode when there is no touching
+#define FT5336_TIMEENTERMONITOR_REG 0x87
+
+// Report rate in Active mode
+#define FT5336_PERIODACTIVE_REG 0x88
+
+// Report rate in Monitor mode
+#define FT5336_PERIODMONITOR_REG 0x89
+
+// The value of the minimum allowed angle while Rotating gesture mode
+#define FT5336_RADIAN_VALUE_REG 0x91
+
+// Maximum offset while Moving Left and Moving Right gesture
+#define FT5336_OFFSET_LEFT_RIGHT_REG 0x92
+
+// Maximum offset while Moving Up and Moving Down gesture
+#define FT5336_OFFSET_UP_DOWN_REG 0x93
+
+// Minimum distance while Moving Left and Moving Right gesture
+#define FT5336_DISTANCE_LEFT_RIGHT_REG 0x94
+
+// Minimum distance while Moving Up and Moving Down gesture
+#define FT5336_DISTANCE_UP_DOWN_REG 0x95
+
+// Maximum distance while Zoom In and Zoom Out gesture
+#define FT5336_DISTANCE_ZOOM_REG 0x96
+
+// High 8-bit of LIB Version info
+#define FT5336_LIB_VER_H_REG 0xA1
+
+// Low 8-bit of LIB Version info
+#define FT5336_LIB_VER_L_REG 0xA2
+
+// Chip Selecting
+#define FT5336_CIPHER_REG 0xA3
+
+// Interrupt mode register (used when in interrupt mode
+#define FT5336_GMODE_REG 0xA4
+
+#define FT5336_G_MODE_INTERRUPT_MASK 0x03
+#define FT5336_G_MODE_INTERRUPT_SHIFT 0x00
+
+// Possible values of FT5336_GMODE_REG
+#define FT5336_G_MODE_INTERRUPT_POLLING 0x00
+#define FT5336_G_MODE_INTERRUPT_TRIGGER 0x01
+
+// Current power mode the FT5336 system is in (R)
+#define FT5336_PWR_MODE_REG 0xA5
+
+// FT5336 firmware version
+#define FT5336_FIRMID_REG 0xA6
+
+// FT5336 Chip identification register
+#define FT5336_CHIP_ID_REG 0xA8
+
+// Possible values of FT5336_CHIP_ID_REG
+#define FT5336_ID_VALUE 0x51
+
+// Release code version
+#define FT5336_RELEASE_CODE_ID_REG 0xAF
+
+// Current operating mode the FT5336 system is in (R)
+#define FT5336_STATE_REG 0xBC
+
+#endif /* _FT5336_H */
diff --git a/drivers/ginput/touch/FT5336/gmouse_lld_FT5336.c b/drivers/ginput/touch/FT5336/gmouse_lld_FT5336.c
new file mode 100644
index 00000000..a55bef65
--- /dev/null
+++ b/drivers/ginput/touch/FT5336/gmouse_lld_FT5336.c
@@ -0,0 +1,106 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+
+#define GMOUSE_DRIVER_VMT GMOUSEVMT_FT5336
+#include "src/ginput/ginput_driver_mouse.h"
+
+// Get the hardware interface
+#include "gmouse_lld_FT5336_board.h"
+
+// Hardware definitions
+#include "drivers/ginput/touch/FT5336/ft5336.h"
+
+static bool_t ft5336Init(GMouse* m, unsigned driverinstance)
+{
+ // Initialize the board stuff
+ if (!init_board(m, driverinstance)) {
+ return FALSE;
+ }
+
+ // We need at least 200 ms worth of delay here...
+ gfxSleepMilliseconds(200);
+
+ // Check Chip ID
+ if (read_byte(m, FT5336_CHIP_ID_REG) != FT5336_ID_VALUE) {
+ return FALSE;
+ }
+
+ // Disable interrupts. We use this chip in polling mode
+ write_reg(m, FT5336_GMODE_REG, (FT5336_G_MODE_INTERRUPT_POLLING & (FT5336_G_MODE_INTERRUPT_MASK >> FT5336_G_MODE_INTERRUPT_SHIFT)) << FT5336_G_MODE_INTERRUPT_SHIFT);
+
+/*
+ // Init default values. (From NHD-3.5-320240MF-ATXL-CTP-1 datasheet)
+ // Valid touching detect threshold
+ write_reg(m, FT5336_TH_GROUP_REG, 0x16);
+
+ // Touch difference threshold
+ write_reg(m, FT5336_TH_DIFF_REG, 0xA0);
+
+ // Delay to enter 'Monitor' status (s)
+ write_reg(m, FT5336_TIMEENTERMONITOR_REG, 0x0A);
+
+ // Period of 'Active' status (ms)
+ write_reg(m, FT5336_PERIODACTIVE_REG, 0x06);
+
+ // Timer to enter 'idle' when in 'Monitor' (ms)
+ write_reg(m, FT5336_PERIODMONITOR_REG, 0x28);
+*/
+ return TRUE;
+}
+
+static bool_t ft5336ReadXYZ(GMouse* m, GMouseReading* pdr)
+{
+ // Assume not touched.
+ pdr->buttons = 0;
+ pdr->z = 0;
+
+ // Only take a reading if exactly one touch contact point
+ if (read_byte(m, FT5336_TD_STAT_REG) == 1) {
+ // Get and return X, Y an Z values
+ pdr->y = (coord_t)(read_word(m, FT5336_P1_XH_REG) & 0x0FFF);
+ pdr->x = (coord_t)(read_word(m, FT5336_P1_YH_REG) & 0x0FFF);
+ pdr->z = 1;
+ }
+
+ return TRUE;
+}
+
+const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
+ {
+ GDRIVER_TYPE_TOUCH,
+ GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN,
+ sizeof(GMouse) + GMOUSE_FT5336_BOARD_DATA_SIZE,
+ _gmouseInitDriver,
+ _gmousePostInitDriver,
+ _gmouseDeInitDriver
+ },
+ 1, // z_max - (currently?) not supported
+ 0, // z_min - (currently?) not supported
+ 1, // z_touchon
+ 0, // z_touchoff
+ { // pen_jitter
+ GMOUSE_FT5336_PEN_CALIBRATE_ERROR, // calibrate
+ GMOUSE_FT5336_PEN_CLICK_ERROR, // click
+ GMOUSE_FT5336_PEN_MOVE_ERROR // move
+ },
+ { // finger_jitter
+ GMOUSE_FT5336_FINGER_CALIBRATE_ERROR, // calibrate
+ GMOUSE_FT5336_FINGER_CLICK_ERROR, // click
+ GMOUSE_FT5336_FINGER_MOVE_ERROR // move
+ },
+ ft5336Init, // init
+ 0, // deinit
+ ft5336ReadXYZ, // get
+ 0, // calsave
+ 0 // calload
+}};
+
+#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
diff --git a/drivers/ginput/touch/FT5336/gmouse_lld_FT5336_board_template.h b/drivers/ginput/touch/FT5336/gmouse_lld_FT5336_board_template.h
new file mode 100644
index 00000000..1daa0b1e
--- /dev/null
+++ b/drivers/ginput/touch/FT5336/gmouse_lld_FT5336_board_template.h
@@ -0,0 +1,59 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#ifndef _GINPUT_LLD_MOUSE_BOARD_H
+#define _GINPUT_LLD_MOUSE_BOARD_H
+
+// Resolution and Accuracy Settings
+#define GMOUSE_FT5336_PEN_CALIBRATE_ERROR 8
+#define GMOUSE_FT5336_PEN_CLICK_ERROR 6
+#define GMOUSE_FT5336_PEN_MOVE_ERROR 4
+#define GMOUSE_FT5336_FINGER_CALIBRATE_ERROR 14
+#define GMOUSE_FT5336_FINGER_CLICK_ERROR 18
+#define GMOUSE_FT5336_FINGER_MOVE_ERROR 14
+
+// How much extra data to allocate at the end of the GMouse structure for the board's use
+#define GMOUSE_FT5336_BOARD_DATA_SIZE 0
+
+// Set this to TRUE if you want self-calibration.
+// NOTE: This is not as accurate as real calibration.
+// It requires the orientation of the touch panel to match the display.
+// It requires the active area of the touch panel to exactly match the display size.
+#define GMOUSE_FT5336_SELF_CALIBRATE FALSE
+
+static bool_t init_board(GMouse* m, unsigned instance)
+{
+ (void)m;
+ (void)instance;
+
+ return TRUE;
+}
+
+static void write_reg(GMouse* m, uint8_t reg, uint8_t val)
+{
+ (void)m;
+ (void)reg;
+ (void)val;
+}
+
+static uint8_t read_byte(GMouse* m, uint8_t reg)
+{
+ (void)m;
+ (void)reg;
+
+ return (uint16_t)0x00;
+}
+
+static uint16_t read_word(GMouse* m, uint8_t reg)
+{
+ (void)m;
+ (void)reg;
+
+ return (uint16_t)0x0000;
+}
+
+#endif /* _GINPUT_LLD_MOUSE_BOARD_H */
diff --git a/gfxconf.example.h b/gfxconf.example.h
index 52c129ef..d46bbae2 100644
--- a/gfxconf.example.h
+++ b/gfxconf.example.h
@@ -35,13 +35,15 @@
//#define GFX_USE_OS_ECOS FALSE
//#define GFX_USE_OS_RAWRTOS FALSE
//#define GFX_USE_OS_RAW32 FALSE
-// #define GOS_RAW_HEAP_SIZE 0
// #define INTERRUPTS_OFF() optional_code
// #define INTERRUPTS_ON() optional_code
// Options that (should where relevant) apply to all operating systems
// #define GFX_COMPILER GFX_COMPILER_UNKNOWN
+// #define GFX_CPU GFX_CPU_UNKNOWN
+// #define GFX_OS_HEAP_SIZE 0
// #define GFX_NO_OS_INIT FALSE
+// #define GFX_OS_INIT_NO_WARNING FALSE
// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine
// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine
diff --git a/src/gos/gos.mk b/src/gos/gos.mk
index 7db246d2..1c3a86a5 100644
--- a/src/gos/gos.mk
+++ b/src/gos/gos.mk
@@ -11,5 +11,7 @@ GFXSRC += $(GFXLIB)/src/gos/gos_chibios.c \
$(GFXLIB)/src/gos/gos_raw32.c \
$(GFXLIB)/src/gos/gos_ecos.c \
$(GFXLIB)/src/gos/gos_rawrtos.c \
- $(GFXLIB)/src/gos/gos_arduino.c
+ $(GFXLIB)/src/gos/gos_arduino.c \
+ $(GFXLIB)/src/gos/gos_x_threads.c \
+ $(GFXLIB)/src/gos/gos_x_heap.c
diff --git a/src/gos/gos_arduino.c b/src/gos/gos_arduino.c
index 380d528a..c565abb9 100644
--- a/src/gos/gos_arduino.c
+++ b/src/gos/gos_arduino.c
@@ -11,7 +11,8 @@
#include <string.h> // Prototype for memcpy()
-static void _gosThreadsInit(void);
+void _gosHeapInit(void);
+void _gosThreadsInit(void);
/*********************************************************
* Initialise
@@ -23,7 +24,12 @@ void _gosInit(void)
* On the other hand the C runtime should still already be initialized before
* getting here!
*/
- #warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #if !GFX_OS_INIT_NO_WARNING
+ #warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #endif
+
+ // Start the heap allocator
+ _gosHeapInit();
// Start the scheduler
_gosThreadsInit();
@@ -53,488 +59,16 @@ void gfxExit(void) {
dummy++;
}
-/*********************************************************
- * Head allocation functions
- *********************************************************/
-
-#include <stdlib.h> // Prototype for malloc(), realloc() and free()
-
-void *gfxAlloc(size_t sz) {
- return malloc(sz);
-}
-
-void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
- (void) oldsz;
- return realloc(ptr, newsz);
-}
-
-void gfxFree(void *ptr) {
- free(ptr);
-}
-
-/*********************************************************
- * Semaphores and critical region functions
- *********************************************************/
-
-#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
- #define INTERRUPTS_OFF()
- #define INTERRUPTS_ON()
-#endif
-
-void gfxSystemLock(void) {
- INTERRUPTS_OFF();
-}
-
-void gfxSystemUnlock(void) {
- INTERRUPTS_ON();
-}
-
-void gfxMutexInit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxMutexEnter(gfxMutex *pmutex) {
- INTERRUPTS_OFF();
- while (pmutex[0]) {
- INTERRUPTS_ON();
- gfxYield();
- INTERRUPTS_OFF();
- }
- pmutex[0] = 1;
- INTERRUPTS_ON();
-}
-
-void gfxMutexExit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
- psem->cnt = val;
- psem->limit = limit;
-}
-
-bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Convert our delay to ticks
- switch (ms) {
- case TIME_IMMEDIATE:
- delay = TIME_IMMEDIATE;
- break;
- case TIME_INFINITE:
- delay = TIME_INFINITE;
- break;
- default:
- delay = gfxMillisecondsToTicks(ms);
- if (!delay) delay = 1;
- starttm = gfxSystemTicks();
- }
-
- INTERRUPTS_OFF();
- while (psem->cnt <= 0) {
- INTERRUPTS_ON();
- // Check if we have exceeded the defined delay
- switch (delay) {
- case TIME_IMMEDIATE:
- return FALSE;
- case TIME_INFINITE:
- break;
- default:
- if (gfxSystemTicks() - starttm >= delay)
- return FALSE;
- break;
- }
- gfxYield();
- INTERRUPTS_OFF();
- }
- psem->cnt--;
- INTERRUPTS_ON();
- return TRUE;
-}
-
-bool_t gfxSemWaitI(gfxSem *psem) {
- if (psem->cnt <= 0)
- return FALSE;
- psem->cnt--;
- return TRUE;
-}
-
-void gfxSemSignal(gfxSem *psem) {
- INTERRUPTS_OFF();
- gfxSemSignalI(psem);
- INTERRUPTS_ON();
-}
-
-void gfxSemSignalI(gfxSem *psem) {
- if (psem->cnt < psem->limit)
- psem->cnt++;
-}
/*********************************************************
* Sleep functions
*********************************************************/
-void gfxSleepMilliseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
+systemticks_t gfxSystemTicks(void) {
+ return millis();
}
-
-void gfxSleepMicroseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms/1000);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-/*********************************************************
- * Threading functions
- *********************************************************/
-
-/**
- * There are some compilers we know how they store the jmpbuf. For those
- * we can use the constant macro definitions. For others we have to "auto-detect".
- * Auto-detection is hairy and there is no guarantee it will work on all architectures.
- * For those it doesn't - read the compiler manuals and the library source code to
- * work out the correct macro values.
- * You can use the debugger to work out the values for your compiler and put them here.
- * Defining these macros as constant values makes the system behavior guaranteed but also
- * makes your code compiler and cpu architecture dependent. It also saves a heap of code
- * and a few bytes of RAM.
- */
-#if GFX_COMPILER == GFX_COMPILER_MINGW32
- #define AUTO_DETECT_MASK FALSE
- #define STACK_DIR_UP FALSE
- #define MASK1 0x00000011
- #define MASK2 0x00000000
- #define STACK_BASE 12
-#else
- // Use auto-detection of the stack frame format
- // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
- #define AUTO_DETECT_MASK TRUE
- #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
- #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
- #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
- #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
- static bool_t stackdirup;
- static uint32_t jmpmask1;
- static uint32_t jmpmask2;
- static size_t stackbase;
-#endif
-
-#include <setjmp.h> /* jmp_buf, setjmp(), longjmp() */
-
-/**
- * Some compilers define a _setjmp() and a setjmp().
- * The difference between them is that setjmp() saves the signal masks.
- * That is of no use to us so prefer to use the _setjmp() methods.
- * If they don't exist compile them to be the standard setjmp() function.
- * Similarly for longjmp().
- */
-#if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _setjmp setjmp
-#endif
-#if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _longjmp longjmp
-#endif
-
-typedef struct thread {
- struct thread * next; // Next thread
- int flags; // Flags
- #define FLG_THD_ALLOC 0x0001
- #define FLG_THD_MAIN 0x0002
- #define FLG_THD_DEAD 0x0004
- #define FLG_THD_WAIT 0x0008
- size_t size; // Size of the thread stack (including this structure)
- threadreturn_t (*fn)(void *param); // Thread function
- void * param; // Parameter for the thread function
- jmp_buf cxt; // The current thread context.
-} thread;
-
-typedef struct threadQ {
- thread *head;
- thread *tail;
-} threadQ;
-
-static threadQ readyQ; // The list of ready threads
-static threadQ deadQ; // Where we put threads waiting to be deallocated
-static thread * current; // The current running thread
-static thread mainthread; // The main thread context
-
-static void Qinit(threadQ * q) {
- q->head = q->tail = 0;
-}
-
-static void Qadd(threadQ * q, thread *t) {
- t->next = 0;
- if (q->head) {
- q->tail->next = t;
- q->tail = t;
- } else
- q->head = q->tail = t;
-}
-
-static thread *Qpop(threadQ * q) {
- struct thread * t;
-
- if (!q->head)
- return 0;
- t = q->head;
- q->head = t->next;
- return t;
-}
-
-#if AUTO_DETECT_MASK
- // The structure for the saved stack frame information
- typedef struct saveloc {
- char * localptr;
- jmp_buf cxt;
- } saveloc;
-
- // A pointer to our auto-detection buffer.
- static saveloc *pframeinfo;
-
- /* These functions are not static to prevent the compiler removing them as functions */
-
- void get_stack_state(void) {
- char* c;
- pframeinfo->localptr = (char *)&c;
- _setjmp(pframeinfo->cxt);
- }
-
- void get_stack_state_in_fn(void) {
- pframeinfo++;
- get_stack_state();
- pframeinfo--;
- }
-#endif
-
-static void _gosThreadsInit(void) {
- Qinit(&readyQ);
- current = &mainthread;
- current->next = 0;
- current->size = sizeof(thread);
- current->flags = FLG_THD_MAIN;
- current->fn = 0;
- current->param = 0;
-
- #if AUTO_DETECT_MASK
- {
- uint32_t i;
- char ** pout;
- char ** pin;
- size_t diff;
- char * framebase;
-
- // Allocate a buffer to store our test data
- pframeinfo = gfxAlloc(sizeof(saveloc)*2);
-
- // Get details of the stack frame from within a function
- get_stack_state_in_fn();
-
- // Get details of the stack frame outside the function
- get_stack_state();
-
- /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
- stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
- pout = (char **)pframeinfo[0].cxt;
- pin = (char **)pframeinfo[1].cxt;
- diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
- framebase = pframeinfo[0].localptr;
- jmpmask1 = jmpmask2 = 0;
- for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
- if ((size_t)(*pout - *pin) == diff) {
- if (i < 32)
- jmpmask1 |= 1 << i;
- else
- jmpmask2 |= 1 << (i-32);
-
- if (stackdirup) {
- if (framebase > *pout)
- framebase = *pout;
- } else {
- if (framebase < *pout)
- framebase = *pout;
- }
- }
- }
- stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
-
- // Clean up
- gfxFree(pframeinfo);
- }
- #endif
-}
-
-gfxThreadHandle gfxThreadMe(void) {
- return (gfxThreadHandle)current;
-}
-
-void gfxYield(void) {
- if (!_setjmp(current->cxt)) {
- // Add us back to the Queue
- Qadd(&readyQ, current);
-
- // Check if there are dead processes to deallocate
- while ((current = Qpop(&deadQ)))
- gfxFree(current);
-
- // Run the next process
- current = Qpop(&readyQ);
- _longjmp(current->cxt, 1);
- }
-}
-
-// This routine is not currently public - but it could be.
-void gfxThreadExit(threadreturn_t ret) {
- // Save the results
- current->param = (void *)ret;
- current->flags |= FLG_THD_DEAD;
-
- // Add us to the dead list if we need deallocation as we can't free ourselves.
- // If someone is waiting on the thread they will do the cleanup.
- if ((current->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
- Qadd(&deadQ, current);
-
- // Switch to the next task
- current = Qpop(&readyQ);
- if (!current)
- gfxExit(); // Oops - this should never happen!
- _longjmp(current->cxt, 1);
-}
-
-gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
- thread * t;
- (void) prio;
-
- // Ensure we have a minimum stack size
- if (stacksz < sizeof(thread)+64) {
- stacksz = sizeof(thread)+64;
- stackarea = 0;
- }
-
- if (stackarea) {
- t = (thread *)stackarea;
- t->flags = 0;
- } else {
- t = (thread *)gfxAlloc(stacksz);
- if (!t)
- return 0;
- t->flags = FLG_THD_ALLOC;
- }
- t->size = stacksz;
- t->fn = fn;
- t->param = param;
- if (_setjmp(t->cxt)) {
- // This is the new thread - call the function!
- gfxThreadExit(current->fn(current->param));
-
- // We never get here
- return 0;
- }
-
- // Move the stack frame and relocate the context data
- {
- char ** s;
- char * nf;
- int diff;
- uint32_t i;
-
- // Copy the stack frame
- #if AUTO_DETECT_MASK
- if (STACK_DIR_UP) { // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- } else { // Stack grows down
- nf = (char *)(t) + stacksz - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- }
- #elif STACK_DIR_UP
- // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- #else
- // Stack grows down
- nf = (char *)(t) + size - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- #endif
-
- // Relocate the context data
- s = (char **)(t->cxt);
- diff = nf - (char *)&t;
-
- // Relocate the elements we know need to be relocated
- for (i = 1; i && i < MASK1; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #ifdef MASK2
- for (i = 1; i && i < MASK2; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #endif
- }
-
- // Add this thread to the ready queue
- Qadd(&readyQ, t);
- return t;
-}
-
-threadreturn_t gfxThreadWait(gfxThreadHandle th) {
- thread * t;
-
- t = th;
- if (t == current)
- return -1;
-
- // Mark that we are waiting
- t->flags |= FLG_THD_WAIT;
-
- // Wait for the thread to die
- while(!(t->flags & FLG_THD_DEAD))
- gfxYield();
-
- // Unmark
- t->flags &= ~FLG_THD_WAIT;
-
- // Clean up resources if needed
- if (t->flags & FLG_THD_ALLOC)
- gfxFree(t);
-
- // Return the status left by the dead process
- return (threadreturn_t)t->param;
+systemticks_t gfxMillisecondsToTicks(delaytime_t ms) {
+ return ms;
}
-#endif /* GFX_USE_OS_RAW32 */
+#endif /* GFX_USE_OS_ARDUINO */
diff --git a/src/gos/gos_arduino.h b/src/gos/gos_arduino.h
index fc9e7073..6a18aaec 100644
--- a/src/gos/gos_arduino.h
+++ b/src/gos/gos_arduino.h
@@ -44,70 +44,26 @@ typedef bool bool_t;
typedef uint32_t size_t;
#endif
-typedef uint32_t delaytime_t;
-typedef uint32_t systemticks_t;
-typedef short semcount_t;
-typedef int threadreturn_t;
-typedef int threadpriority_t;
-
-#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
-#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
-
-#define TIME_IMMEDIATE 0
-#define TIME_INFINITE ((delaytime_t)-1)
-#define MAX_SEMAPHORE_COUNT 0x7FFF
-#define LOW_PRIORITY 0
-#define NORMAL_PRIORITY 1
-#define HIGH_PRIORITY 2
-
-typedef struct {
- semcount_t cnt;
- semcount_t limit;
-} gfxSem;
-
-typedef uint32_t gfxMutex;
-typedef void * gfxThreadHandle;
-
-#define gfxThreadClose(thread)
-#define gfxMutexDestroy(pmutex)
-#define gfxSemDestroy(psem)
-#define gfxSemCounter(psem) ((psem)->cnt)
-#define gfxSemCounterI(psem) ((psem)->cnt)
-
-#define gfxSystemTicks() millis()
-#define gfxMillisecondsToTicks(ms) (ms)
-
#ifdef __cplusplus
extern "C" {
#endif
void gfxHalt(const char *msg);
void gfxExit(void);
- void *gfxAlloc(size_t sz);
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
- void gfxFree(void *ptr);
- void gfxYield(void);
- void gfxSleepMilliseconds(delaytime_t ms);
- void gfxSleepMicroseconds(delaytime_t ms);
- //systemticks_t gfxSystemTicks(void);
- //systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
- void gfxSystemLock(void);
- void gfxSystemUnlock(void);
- void gfxMutexInit(gfxMutex *pmutex);
- void gfxMutexEnter(gfxMutex *pmutex);
- void gfxMutexExit(gfxMutex *pmutex);
- void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
- bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
- bool_t gfxSemWaitI(gfxSem *psem);
- void gfxSemSignal(gfxSem *psem);
- void gfxSemSignalI(gfxSem *psem);
- gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
- threadreturn_t gfxThreadWait(gfxThreadHandle thread);
- gfxThreadHandle gfxThreadMe(void);
#ifdef __cplusplus
}
#endif
+/*===========================================================================*/
+/* Use the generic thread handling and heap handling */
+/*===========================================================================*/
+
+#define GOS_NEED_X_THREADS TRUE
+#define GOS_NEED_X_HEAP TRUE
+
+#include "gos_x_threads.h"
+#include "gos_x_heap.h"
+
#endif /* GFX_USE_OS_ARDUINO */
#endif /* _GOS_ARDUINO_H */
diff --git a/src/gos/gos_chibios.c b/src/gos/gos_chibios.c
index 62f5d8ee..4c79bd3d 100644
--- a/src/gos/gos_chibios.c
+++ b/src/gos/gos_chibios.c
@@ -48,7 +48,7 @@ void _gosInit(void)
chSysInit();
}
#endif
- #else
+ #elif !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call halInit() and chSysInit() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_ecos.c b/src/gos/gos_ecos.c
index 16ce821b..cdad86da 100644
--- a/src/gos/gos_ecos.c
+++ b/src/gos/gos_ecos.c
@@ -13,7 +13,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for eCos is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call cyg_scheduler_start() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_freertos.c b/src/gos/gos_freertos.c
index dbdfd22e..7b978738 100644
--- a/src/gos/gos_freertos.c
+++ b/src/gos/gos_freertos.c
@@ -26,7 +26,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for FreeRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call vTaskStartScheduler() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_mk.c b/src/gos/gos_mk.c
index 71267233..1b033206 100644
--- a/src/gos/gos_mk.c
+++ b/src/gos/gos_mk.c
@@ -14,3 +14,5 @@
#include "gos_raw32.c"
#include "gos_rawrtos.c"
#include "gos_win32.c"
+#include "gos_x_threads.c"
+#include "gos_x_heap.c"
diff --git a/src/gos/gos_options.h b/src/gos/gos_options.h
index 8fb4f51b..600c3085 100644
--- a/src/gos/gos_options.h
+++ b/src/gos/gos_options.h
@@ -74,7 +74,7 @@
* @details Defaults to FALSE
*/
#ifndef GFX_USE_OS_ARDUINO
- #define GFX_USE_OS_ARDUINO FALSE
+ #define GFX_USE_OS_ARDUINO FALSE
#endif
/**
* @}
@@ -88,12 +88,35 @@
* @note This is setting enables optimisations that are compiler specific. It does
* not need to be specified as reasonable defaults and various auto-detection
* will happen as required.
+ * @note Currently only used by ugfx generic thread handling (GOS_USE_OS_RAW32 and GOS_USE_OS_ARDUINO)
*/
#ifndef GFX_COMPILER
#define GFX_COMPILER GFX_COMPILER_UNKNOWN
#endif
#define GFX_COMPILER_UNKNOWN 0 // Unknown compiler
#define GFX_COMPILER_MINGW32 1 // MingW32 (x86) compiler for windows
+ /**
+ * @brief Enable cpu specific code
+ * @details Defaults to GFX_CPU_UNKNOWN
+ * @note This is setting enables optimisations that are cpu specific. It does
+ * not need to be specified as reasonable defaults and various auto-detection
+ * will happen as required.
+ * @note Currently only used by ugfx generic thread handling (GOS_USE_OS_RAW32 and GOS_USE_OS_ARDUINO)
+ * @{
+ */
+ #ifndef GFX_CPU
+ #define GFX_CPU GFX_CPU_UNKNOWN
+ #endif
+ #define GFX_CPU_UNKNOWN 0 //**< Unknown cpu
+ #define GFX_CPU_CORTEX_M0 1 //**< Cortex M0
+ #define GFX_CPU_CORTEX_M1 2 //**< Cortex M1
+ #define GFX_CPU_CORTEX_M2 3 //**< Cortex M2
+ #define GFX_CPU_CORTEX_M3 4 //**< Cortex M3
+ #define GFX_CPU_CORTEX_M4 5 //**< Cortex M4
+ #define GFX_CPU_CORTEX_M4_FP 6 //**< Cortex M4 with hardware floating point
+ #define GFX_CPU_CORTEX_M7 7 //**< Cortex M7
+ #define GFX_CPU_CORTEX_M7_FP 8 //**< Cortex M7 with hardware floating point
+ /** @} */
/**
* @brief Should uGFX avoid initializing the operating system
* @details Defaults to FALSE
@@ -109,6 +132,16 @@
#define GFX_NO_OS_INIT FALSE
#endif
/**
+ * @brief Turn off warnings about initializing the operating system
+ * @details Defaults to FALSE
+ * @note This is only relevant where GOS cannot initialise the operating
+ * system automatically or the operating system initialisation has been
+ * explicitly turned off.
+ */
+ #ifndef GFX_OS_INIT_NO_WARNING
+ #define GFX_OS_INIT_NO_WARNING FALSE
+ #endif
+ /**
* @brief Should uGFX stuff be added to the FreeRTOS+Tracer
* @details Defaults to FALSE
*/
@@ -117,7 +150,8 @@
#endif
/**
* @brief How much RAM should uGFX use for the heap
- * @details Defaults to 0. Only valid with GFX_USE_OS_RAW32
+ * @details Defaults to 0.
+ * @note Only used when the generic ugfx heap code is used (GFX_USE_OS_RAW32 and GFX_USE_OS_ARDUINO)
* @note If 0 then the standard C runtime malloc(), free() and realloc()
* are used.
* @note If it is non-zero then this is the number of bytes of RAM
@@ -125,8 +159,8 @@
* runtime routines will be used and a new routine @p gfxAddHeapBlock()
* is added allowing the user to add extra memory blocks to the heap.
*/
- #ifndef GOS_RAW_HEAP_SIZE
- #define GOS_RAW_HEAP_SIZE 0
+ #ifndef GFX_OS_HEAP_SIZE
+ #define GFX_OS_HEAP_SIZE 0
#endif
/** @} */
diff --git a/src/gos/gos_raw32.c b/src/gos/gos_raw32.c
index c454a68b..4e61feb9 100644
--- a/src/gos/gos_raw32.c
+++ b/src/gos/gos_raw32.c
@@ -12,14 +12,8 @@
#if GFX_USE_OS_RAW32
-#include <string.h> // Prototype for memcpy()
-
-#if GOS_RAW_HEAP_SIZE != 0
- static void _gosHeapInit(void);
-#else
- #define _gosHeapInit()
-#endif
-static void _gosThreadsInit(void);
+void _gosHeapInit(void);
+void _gosThreadsInit(void);
/*********************************************************
* Initialise
@@ -31,7 +25,9 @@ void _gosInit(void)
* On the other hand the C runtime should still already be initialized before
* getting here!
*/
- #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #if !GFX_OS_INIT_NO_WARNING
+ #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #endif
// Set up the heap allocator
_gosHeapInit();
@@ -46,7 +42,7 @@ void _gosDeinit(void)
}
/*********************************************************
- * For WIn32 emulation - automatically add the tick functions
+ * For Win32 emulation - automatically add the tick functions
* the user would normally have to provide for bare metal.
*********************************************************/
@@ -98,651 +94,4 @@ void gfxExit(void) {
#endif
}
-/*********************************************************
- * Head allocation functions
- *********************************************************/
-
-#if GOS_RAW_HEAP_SIZE == 0
- #include <stdlib.h> // Prototype for malloc(), realloc() and free()
-
- void *gfxAlloc(size_t sz) {
- return malloc(sz);
- }
-
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
- (void) oldsz;
- return realloc(ptr, newsz);
- }
-
- void gfxFree(void *ptr) {
- free(ptr);
- }
-
-#else
-
- // Slot structure - user memory follows
- typedef struct memslot {
- struct memslot *next; // The next memslot
- size_t sz; // Includes the size of this memslot.
- } memslot;
-
- // Free Slot - immediately follows the memslot structure
- typedef struct freeslot {
- memslot *nextfree; // The next free slot
- } freeslot;
-
- #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
- #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
- #define Ptr2Slot(p) ((memslot *)(p) - 1)
- #define Slot2Ptr(pslot) ((pslot)+1)
-
- static memslot * firstSlot;
- static memslot * lastSlot;
- static memslot * freeSlots;
- static char heap[GOS_RAW_HEAP_SIZE];
-
- static void _gosHeapInit(void) {
- lastSlot = 0;
- gfxAddHeapBlock(heap, GOS_RAW_HEAP_SIZE);
- }
-
- void gfxAddHeapBlock(void *ptr, size_t sz) {
- if (sz < sizeof(memslot)+sizeof(freeslot))
- return;
-
- if (lastSlot)
- lastSlot->next = (memslot *)ptr;
- else
- firstSlot = lastSlot = freeSlots = (memslot *)ptr;
-
- lastSlot->next = 0;
- lastSlot->sz = sz;
- NextFree(lastSlot) = 0;
- }
-
- void *gfxAlloc(size_t sz) {
- register memslot *prev, *p, *new;
-
- if (!sz) return 0;
- sz = GetSlotSize(sz);
- for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
- // Loop till we have a block big enough
- if (p->sz < sz)
- continue;
- // Can we save some memory by splitting this block?
- if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
- p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = NextFree(p);
- NextFree(p) = new;
- }
- // Remove it from the free list
- if (prev)
- NextFree(prev) = NextFree(p);
- else
- freeSlots = NextFree(p);
- // Return the result found
- return Slot2Ptr(p);
- }
- // No slots large enough
- return 0;
- }
-
- void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
- register memslot *prev, *p, *new;
- (void) oldsz;
-
- if (!ptr)
- return gfxAlloc(sz);
- if (!sz) {
- gfxFree(ptr);
- return 0;
- }
-
- p = Ptr2Slot(ptr);
- sz = GetSlotSize(sz);
-
- // If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
- }
- }
-
- // If this block is large enough we are nearly done
- if (sz < p->sz) {
- // Can we save some memory by splitting this block?
- if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
- p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = freeSlots;
- freeSlots = new;
- }
- return Slot2Ptr(p);
- }
-
- // We need to do this the hard way
- if ((new = gfxAlloc(sz)))
- return 0;
- memcpy(new, ptr, p->sz - sizeof(memslot));
- gfxFree(ptr);
- return new;
- }
-
- void gfxFree(void *ptr) {
- register memslot *prev, *p, *new;
-
- if (!ptr)
- return;
-
- p = Ptr2Slot(ptr);
-
- // If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
- }
- }
-
- // Add it into the free chain
- NextFree(p) = freeSlots;
- freeSlots = p;
- }
-#endif
-
-/*********************************************************
- * Semaphores and critical region functions
- *********************************************************/
-
-#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
- #define INTERRUPTS_OFF()
- #define INTERRUPTS_ON()
-#endif
-
-void gfxSystemLock(void) {
- INTERRUPTS_OFF();
-}
-
-void gfxSystemUnlock(void) {
- INTERRUPTS_ON();
-}
-
-void gfxMutexInit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxMutexEnter(gfxMutex *pmutex) {
- INTERRUPTS_OFF();
- while (pmutex[0]) {
- INTERRUPTS_ON();
- gfxYield();
- INTERRUPTS_OFF();
- }
- pmutex[0] = 1;
- INTERRUPTS_ON();
-}
-
-void gfxMutexExit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
- psem->cnt = val;
- psem->limit = limit;
-}
-
-bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Convert our delay to ticks
- switch (ms) {
- case TIME_IMMEDIATE:
- delay = TIME_IMMEDIATE;
- break;
- case TIME_INFINITE:
- delay = TIME_INFINITE;
- break;
- default:
- delay = gfxMillisecondsToTicks(ms);
- if (!delay) delay = 1;
- starttm = gfxSystemTicks();
- }
-
- INTERRUPTS_OFF();
- while (psem->cnt <= 0) {
- INTERRUPTS_ON();
- // Check if we have exceeded the defined delay
- switch (delay) {
- case TIME_IMMEDIATE:
- return FALSE;
- case TIME_INFINITE:
- break;
- default:
- if (gfxSystemTicks() - starttm >= delay)
- return FALSE;
- break;
- }
- gfxYield();
- INTERRUPTS_OFF();
- }
- psem->cnt--;
- INTERRUPTS_ON();
- return TRUE;
-}
-
-bool_t gfxSemWaitI(gfxSem *psem) {
- if (psem->cnt <= 0)
- return FALSE;
- psem->cnt--;
- return TRUE;
-}
-
-void gfxSemSignal(gfxSem *psem) {
- INTERRUPTS_OFF();
- gfxSemSignalI(psem);
- INTERRUPTS_ON();
-}
-
-void gfxSemSignalI(gfxSem *psem) {
- if (psem->cnt < psem->limit)
- psem->cnt++;
-}
-
-/*********************************************************
- * Sleep functions
- *********************************************************/
-
-void gfxSleepMilliseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-void gfxSleepMicroseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms/1000);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-/*********************************************************
- * Threading functions
- *********************************************************/
-
-/**
- * There are some compilers we know how they store the jmpbuf. For those
- * we can use the constant macro definitions. For others we have to "auto-detect".
- * Auto-detection is hairy and there is no guarantee it will work on all architectures.
- * For those it doesn't - read the compiler manuals and the library source code to
- * work out the correct macro values.
- * You can use the debugger to work out the values for your compiler and put them here.
- * Defining these macros as constant values makes the system behavior guaranteed but also
- * makes your code compiler and cpu architecture dependent. It also saves a heap of code
- * and a few bytes of RAM.
- */
-#if GFX_COMPILER == GFX_COMPILER_MINGW32
- #define AUTO_DETECT_MASK FALSE
- #define STACK_DIR_UP FALSE
- #define MASK1 0x00000011
- #define MASK2 0x00000000
- #define STACK_BASE 12
-#else
- // Use auto-detection of the stack frame format
- // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
- #define AUTO_DETECT_MASK TRUE
- #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
- #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
- #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
- #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
- static bool_t stackdirup;
- static uint32_t jmpmask1;
- static uint32_t jmpmask2;
- static size_t stackbase;
-#endif
-
-#include <setjmp.h> /* jmp_buf, setjmp(), longjmp() */
-
-/**
- * Some compilers define a _setjmp() and a setjmp().
- * The difference between them is that setjmp() saves the signal masks.
- * That is of no use to us so prefer to use the _setjmp() methods.
- * If they don't exist compile them to be the standard setjmp() function.
- * Similarly for longjmp().
- */
-#if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _setjmp setjmp
-#endif
-#if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _longjmp longjmp
-#endif
-
-typedef struct thread {
- struct thread * next; // Next thread
- int flags; // Flags
- #define FLG_THD_ALLOC 0x0001
- #define FLG_THD_MAIN 0x0002
- #define FLG_THD_DEAD 0x0004
- #define FLG_THD_WAIT 0x0008
- size_t size; // Size of the thread stack (including this structure)
- threadreturn_t (*fn)(void *param); // Thread function
- void * param; // Parameter for the thread function
- jmp_buf cxt; // The current thread context.
-} thread;
-
-typedef struct threadQ {
- thread *head;
- thread *tail;
-} threadQ;
-
-static threadQ readyQ; // The list of ready threads
-static threadQ deadQ; // Where we put threads waiting to be deallocated
-static thread * current; // The current running thread
-static thread mainthread; // The main thread context
-
-static void Qinit(threadQ * q) {
- q->head = q->tail = 0;
-}
-
-static void Qadd(threadQ * q, thread *t) {
- t->next = 0;
- if (q->head) {
- q->tail->next = t;
- q->tail = t;
- } else
- q->head = q->tail = t;
-}
-
-static thread *Qpop(threadQ * q) {
- struct thread * t;
-
- if (!q->head)
- return 0;
- t = q->head;
- q->head = t->next;
- return t;
-}
-
-#if AUTO_DETECT_MASK
- // The structure for the saved stack frame information
- typedef struct saveloc {
- char * localptr;
- jmp_buf cxt;
- } saveloc;
-
- // A pointer to our auto-detection buffer.
- static saveloc *pframeinfo;
-
- /* These functions are not static to prevent the compiler removing them as functions */
-
- void get_stack_state(void) {
- char* c;
- pframeinfo->localptr = (char *)&c;
- _setjmp(pframeinfo->cxt);
- }
-
- void get_stack_state_in_fn(void) {
- pframeinfo++;
- get_stack_state();
- pframeinfo--;
- }
-#endif
-
-static void _gosThreadsInit(void) {
- Qinit(&readyQ);
- current = &mainthread;
- current->next = 0;
- current->size = sizeof(thread);
- current->flags = FLG_THD_MAIN;
- current->fn = 0;
- current->param = 0;
-
- #if AUTO_DETECT_MASK
- {
- uint32_t i;
- char ** pout;
- char ** pin;
- size_t diff;
- char * framebase;
-
- // Allocate a buffer to store our test data
- pframeinfo = gfxAlloc(sizeof(saveloc)*2);
-
- // Get details of the stack frame from within a function
- get_stack_state_in_fn();
-
- // Get details of the stack frame outside the function
- get_stack_state();
-
- /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
- stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
- pout = (char **)pframeinfo[0].cxt;
- pin = (char **)pframeinfo[1].cxt;
- diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
- framebase = pframeinfo[0].localptr;
- jmpmask1 = jmpmask2 = 0;
- for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
- if ((size_t)(*pout - *pin) == diff) {
- if (i < 32)
- jmpmask1 |= 1 << i;
- else
- jmpmask2 |= 1 << (i-32);
-
- if (stackdirup) {
- if (framebase > *pout)
- framebase = *pout;
- } else {
- if (framebase < *pout)
- framebase = *pout;
- }
- }
- }
- stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
-
- // Clean up
- gfxFree(pframeinfo);
- }
- #endif
-}
-
-gfxThreadHandle gfxThreadMe(void) {
- return (gfxThreadHandle)current;
-}
-
-void gfxYield(void) {
- if (!_setjmp(current->cxt)) {
- // Add us back to the Queue
- Qadd(&readyQ, current);
-
- // Check if there are dead processes to deallocate
- while ((current = Qpop(&deadQ)))
- gfxFree(current);
-
- // Run the next process
- current = Qpop(&readyQ);
- _longjmp(current->cxt, 1);
- }
-}
-
-// This routine is not currently public - but it could be.
-void gfxThreadExit(threadreturn_t ret) {
- // Save the results
- current->param = (void *)ret;
- current->flags |= FLG_THD_DEAD;
-
- // Add us to the dead list if we need deallocation as we can't free ourselves.
- // If someone is waiting on the thread they will do the cleanup.
- if ((current->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
- Qadd(&deadQ, current);
-
- // Switch to the next task
- current = Qpop(&readyQ);
- if (!current)
- gfxExit(); // Oops - this should never happen!
- _longjmp(current->cxt, 1);
-}
-
-gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
- thread * t;
- (void) prio;
-
- // Ensure we have a minimum stack size
- if (stacksz < sizeof(thread)+64) {
- stacksz = sizeof(thread)+64;
- stackarea = 0;
- }
-
- if (stackarea) {
- t = (thread *)stackarea;
- t->flags = 0;
- } else {
- t = (thread *)gfxAlloc(stacksz);
- if (!t)
- return 0;
- t->flags = FLG_THD_ALLOC;
- }
- t->size = stacksz;
- t->fn = fn;
- t->param = param;
- if (_setjmp(t->cxt)) {
- // This is the new thread - call the function!
- gfxThreadExit(current->fn(current->param));
-
- // We never get here
- return 0;
- }
-
- // Move the stack frame and relocate the context data
- {
- char ** s;
- char * nf;
- int diff;
- uint32_t i;
-
- // Copy the stack frame
- #if AUTO_DETECT_MASK
- if (STACK_DIR_UP) { // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- } else { // Stack grows down
- nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- }
- #elif STACK_DIR_UP
- // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- #else
- // Stack grows down
- nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- #endif
-
- // Relocate the context data
- s = (char **)(t->cxt);
- diff = nf - (char *)&t;
-
- // Relocate the elements we know need to be relocated
- for (i = 1; i && i < MASK1; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #ifdef MASK2
- for (i = 1; i && i < MASK2; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #endif
- }
-
- // Add this thread to the ready queue
- Qadd(&readyQ, t);
- return t;
-}
-
-threadreturn_t gfxThreadWait(gfxThreadHandle th) {
- thread * t;
-
- t = th;
- if (t == current)
- return -1;
-
- // Mark that we are waiting
- t->flags |= FLG_THD_WAIT;
-
- // Wait for the thread to die
- while(!(t->flags & FLG_THD_DEAD))
- gfxYield();
-
- // Unmark
- t->flags &= ~FLG_THD_WAIT;
-
- // Clean up resources if needed
- if (t->flags & FLG_THD_ALLOC)
- gfxFree(t);
-
- // Return the status left by the dead process
- return (threadreturn_t)t->param;
-}
-
#endif /* GFX_USE_OS_RAW32 */
diff --git a/src/gos/gos_raw32.h b/src/gos/gos_raw32.h
index a37b78ff..0fca9223 100644
--- a/src/gos/gos_raw32.h
+++ b/src/gos/gos_raw32.h
@@ -26,18 +26,6 @@
#if GFX_USE_OS_RAW32
/*===========================================================================*/
-/* Special Macros just for a Raw implementation */
-/*===========================================================================*/
-
-/**
- * @brief Set the maximum size of the heap.
- * @note If set to 0 then the C runtime library malloc() and free() are used.
- */
-#ifndef GOS_RAW_HEAP_SIZE
- #define GOS_RAW_HEAP_SIZE 0
-#endif
-
-/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
@@ -60,71 +48,26 @@ typedef unsigned char bool_t;
typedef uint32_t size_t;
#endif
-typedef uint32_t delaytime_t;
-typedef uint32_t systemticks_t;
-typedef short semcount_t;
-typedef int threadreturn_t;
-typedef int threadpriority_t;
-
-#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
-#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
-
-#define TIME_IMMEDIATE 0
-#define TIME_INFINITE ((delaytime_t)-1)
-#define MAX_SEMAPHORE_COUNT 0x7FFF
-#define LOW_PRIORITY 0
-#define NORMAL_PRIORITY 1
-#define HIGH_PRIORITY 2
-
-typedef struct {
- semcount_t cnt;
- semcount_t limit;
-} gfxSem;
-
-typedef uint32_t gfxMutex;
-typedef void * gfxThreadHandle;
-
-#define gfxThreadClose(thread)
-#define gfxMutexDestroy(pmutex)
-#define gfxSemDestroy(psem)
-#define gfxSemCounter(psem) ((psem)->cnt)
-#define gfxSemCounterI(psem) ((psem)->cnt)
-
#ifdef __cplusplus
extern "C" {
#endif
- #if GOS_RAW_HEAP_SIZE != 0
- void gfxAddHeapBlock(void *ptr, size_t sz);
- #endif
-
void gfxHalt(const char *msg);
void gfxExit(void);
- void *gfxAlloc(size_t sz);
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
- void gfxFree(void *ptr);
- void gfxYield(void);
- void gfxSleepMilliseconds(delaytime_t ms);
- void gfxSleepMicroseconds(delaytime_t ms);
- systemticks_t gfxSystemTicks(void);
- systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
- void gfxSystemLock(void);
- void gfxSystemUnlock(void);
- void gfxMutexInit(gfxMutex *pmutex);
- void gfxMutexEnter(gfxMutex *pmutex);
- void gfxMutexExit(gfxMutex *pmutex);
- void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
- bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
- bool_t gfxSemWaitI(gfxSem *psem);
- void gfxSemSignal(gfxSem *psem);
- void gfxSemSignalI(gfxSem *psem);
- gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
- threadreturn_t gfxThreadWait(gfxThreadHandle thread);
- gfxThreadHandle gfxThreadMe(void);
#ifdef __cplusplus
}
#endif
+/*===========================================================================*/
+/* Use the generic thread handling and heap handling */
+/*===========================================================================*/
+
+#define GOS_NEED_X_THREADS TRUE
+#define GOS_NEED_X_HEAP TRUE
+
+#include "gos_x_threads.h"
+#include "gos_x_heap.h"
+
#endif /* GFX_USE_OS_RAW32 */
#endif /* _GOS_RAW32_H */
diff --git a/src/gos/gos_rawrtos.c b/src/gos/gos_rawrtos.c
index c47c85bf..8efe2235 100644
--- a/src/gos/gos_rawrtos.c
+++ b/src/gos/gos_rawrtos.c
@@ -26,7 +26,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for RawRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call raw_os_start() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_x_heap.c b/src/gos/gos_x_heap.c
new file mode 100644
index 00000000..94b74d37
--- /dev/null
+++ b/src/gos/gos_x_heap.c
@@ -0,0 +1,195 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GOS_NEED_X_HEAP
+
+#include <string.h> // Prototype for memcpy()
+
+
+#if GFX_OS_HEAP_SIZE == 0
+ #include <stdlib.h> // Prototype for malloc(), realloc() and free()
+
+ void _gosHeapInit(void) {
+ }
+ void *gfxAlloc(size_t sz) {
+ return malloc(sz);
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
+ (void) oldsz;
+ return realloc(ptr, newsz);
+ }
+
+ void gfxFree(void *ptr) {
+ free(ptr);
+ }
+
+#else
+
+ // Slot structure - user memory follows
+ typedef struct memslot {
+ struct memslot *next; // The next memslot
+ size_t sz; // Includes the size of this memslot.
+ } memslot;
+
+ // Free Slot - immediately follows the memslot structure
+ typedef struct freeslot {
+ memslot *nextfree; // The next free slot
+ } freeslot;
+
+ #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
+ #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
+ #define Ptr2Slot(p) ((memslot *)(p) - 1)
+ #define Slot2Ptr(pslot) ((pslot)+1)
+
+ static memslot * firstSlot;
+ static memslot * lastSlot;
+ static memslot * freeSlots;
+ static char heap[GFX_OS_HEAP_SIZE];
+
+ void _gosHeapInit(void) {
+ lastSlot = 0;
+ gfxAddHeapBlock(heap, GFX_OS_HEAP_SIZE);
+ }
+
+ void gfxAddHeapBlock(void *ptr, size_t sz) {
+ if (sz < sizeof(memslot)+sizeof(freeslot))
+ return;
+
+ if (lastSlot)
+ lastSlot->next = (memslot *)ptr;
+ else
+ firstSlot = lastSlot = freeSlots = (memslot *)ptr;
+
+ lastSlot->next = 0;
+ lastSlot->sz = sz;
+ NextFree(lastSlot) = 0;
+ }
+
+ void *gfxAlloc(size_t sz) {
+ register memslot *prev, *p, *new;
+
+ if (!sz) return 0;
+ sz = GetSlotSize(sz);
+ for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
+ // Loop till we have a block big enough
+ if (p->sz < sz)
+ continue;
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = NextFree(p);
+ NextFree(p) = new;
+ }
+ // Remove it from the free list
+ if (prev)
+ NextFree(prev) = NextFree(p);
+ else
+ freeSlots = NextFree(p);
+ // Return the result found
+ return Slot2Ptr(p);
+ }
+ // No slots large enough
+ return 0;
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
+ register memslot *prev, *p, *new;
+ (void) oldsz;
+
+ if (!ptr)
+ return gfxAlloc(sz);
+ if (!sz) {
+ gfxFree(ptr);
+ return 0;
+ }
+
+ p = Ptr2Slot(ptr);
+ sz = GetSlotSize(sz);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // If this block is large enough we are nearly done
+ if (sz < p->sz) {
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = freeSlots;
+ freeSlots = new;
+ }
+ return Slot2Ptr(p);
+ }
+
+ // We need to do this the hard way
+ if ((new = gfxAlloc(sz)))
+ return 0;
+ memcpy(new, ptr, p->sz - sizeof(memslot));
+ gfxFree(ptr);
+ return new;
+ }
+
+ void gfxFree(void *ptr) {
+ register memslot *prev, *p, *new;
+
+ if (!ptr)
+ return;
+
+ p = Ptr2Slot(ptr);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // Add it into the free chain
+ NextFree(p) = freeSlots;
+ freeSlots = p;
+ }
+#endif
+
+#endif /* GOS_NEED_X_HEAP */
diff --git a/src/gos/gos_x_heap.h b/src/gos/gos_x_heap.h
new file mode 100644
index 00000000..3612989c
--- /dev/null
+++ b/src/gos/gos_x_heap.h
@@ -0,0 +1,62 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * The raw32 GOS implementation supports any 32 bit processor with or without an
+ * underlying operating system. It uses cooperative multi-tasking. Be careful
+ * when writing device drivers not to disturb the assumptions this creates by performing
+ * call-backs to uGFX code unless you define the INTERRUPTS_OFF() and INTERRUPTS_ON() macros.
+ * It still requires some C runtime library support...
+ * enough startup to initialise the stack, interrupts, static data etc and call main().
+ * setjmp() and longjmp() - for threading
+ * memcpy() - for heap and threading
+ * malloc(), realloc and free() - if GFX_OS_HEAP_SIZE == 0
+ *
+ * You must also define the following routines in your own code so that timing functions will work...
+ * systemticks_t gfxSystemTicks(void);
+ * systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+ */
+#ifndef _GOS_X_HEAP_H
+#define _GOS_X_HEAP_H
+
+#if GOS_NEED_X_HEAP
+
+
+/*===========================================================================*/
+/* Special Macros */
+/*===========================================================================*/
+
+/**
+ * @brief Set the maximum size of the heap.
+ * @note If set to 0 then the C runtime library malloc() and free() are used.
+ */
+#ifndef GFX_OS_HEAP_SIZE
+ #define GFX_OS_HEAP_SIZE 0
+#endif
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ #if GFX_OS_HEAP_SIZE != 0
+ void gfxAddHeapBlock(void *ptr, size_t sz);
+ #endif
+
+ void *gfxAlloc(size_t sz);
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
+ void gfxFree(void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOS_NEED_X_HEAP */
+#endif /* _GOS_X_HEAP_H */
diff --git a/src/gos/gos_x_threads.c b/src/gos/gos_x_threads.c
new file mode 100644
index 00000000..8a781b21
--- /dev/null
+++ b/src/gos/gos_x_threads.c
@@ -0,0 +1,672 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GOS_NEED_X_THREADS
+
+/*********************************************************
+ * Semaphores and critical region functions
+ *********************************************************/
+
+#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
+ #define INTERRUPTS_OFF()
+ #define INTERRUPTS_ON()
+#endif
+
+void gfxSystemLock(void) {
+ INTERRUPTS_OFF();
+}
+
+void gfxSystemUnlock(void) {
+ INTERRUPTS_ON();
+}
+
+void gfxMutexInit(gfxMutex *pmutex) {
+ pmutex[0] = 0;
+}
+
+void gfxMutexEnter(gfxMutex *pmutex) {
+ INTERRUPTS_OFF();
+ while (pmutex[0]) {
+ INTERRUPTS_ON();
+ gfxYield();
+ INTERRUPTS_OFF();
+ }
+ pmutex[0] = 1;
+ INTERRUPTS_ON();
+}
+
+void gfxMutexExit(gfxMutex *pmutex) {
+ pmutex[0] = 0;
+}
+
+void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
+ psem->cnt = val;
+ psem->limit = limit;
+}
+
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Convert our delay to ticks
+ starttm = 0;
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ delay = TIME_IMMEDIATE;
+ break;
+ case TIME_INFINITE:
+ delay = TIME_INFINITE;
+ break;
+ default:
+ delay = gfxMillisecondsToTicks(ms);
+ if (!delay) delay = 1;
+ starttm = gfxSystemTicks();
+ }
+
+ INTERRUPTS_OFF();
+ while (psem->cnt <= 0) {
+ INTERRUPTS_ON();
+ // Check if we have exceeded the defined delay
+ switch (delay) {
+ case TIME_IMMEDIATE:
+ return FALSE;
+ case TIME_INFINITE:
+ break;
+ default:
+ if (gfxSystemTicks() - starttm >= delay)
+ return FALSE;
+ break;
+ }
+ gfxYield();
+ INTERRUPTS_OFF();
+ }
+ psem->cnt--;
+ INTERRUPTS_ON();
+ return TRUE;
+}
+
+bool_t gfxSemWaitI(gfxSem *psem) {
+ if (psem->cnt <= 0)
+ return FALSE;
+ psem->cnt--;
+ return TRUE;
+}
+
+void gfxSemSignal(gfxSem *psem) {
+ INTERRUPTS_OFF();
+ gfxSemSignalI(psem);
+ INTERRUPTS_ON();
+}
+
+void gfxSemSignalI(gfxSem *psem) {
+ if (psem->cnt < psem->limit)
+ psem->cnt++;
+}
+
+/*********************************************************
+ * Sleep functions
+ *********************************************************/
+
+void gfxSleepMilliseconds(delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Safety first
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ return;
+ case TIME_INFINITE:
+ while(1)
+ gfxYield();
+ return;
+ }
+
+ // Convert our delay to ticks
+ delay = gfxMillisecondsToTicks(ms);
+ starttm = gfxSystemTicks();
+
+ do {
+ gfxYield();
+ } while (gfxSystemTicks() - starttm < delay);
+}
+
+void gfxSleepMicroseconds(delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Safety first
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ return;
+ case TIME_INFINITE:
+ while(1)
+ gfxYield();
+ return;
+ }
+
+ // Convert our delay to ticks
+ delay = gfxMillisecondsToTicks(ms/1000);
+ starttm = gfxSystemTicks();
+
+ do {
+ gfxYield();
+ } while (gfxSystemTicks() - starttm < delay);
+}
+
+/*********************************************************
+ * Threading functions
+ *********************************************************/
+
+/** For each scheduler the following need to be defined...
+ *
+ * void _gfxThreadsInit(void); - Initialise the scheduler
+ * void _gfxStartThread(thread *oldt, thread *newt); - Start a new thread
+ * void _gfxTaskSwitch(thread *oldt, thread *newt); - Switch to a different thread
+ *
+ */
+
+typedef struct thread {
+ struct thread * next; // Next thread
+ int flags; // Flags
+ #define FLG_THD_ALLOC 0x0001
+ #define FLG_THD_MAIN 0x0002
+ #define FLG_THD_DEAD 0x0004
+ #define FLG_THD_WAIT 0x0008
+ size_t size; // Size of the thread stack (including this structure)
+ threadreturn_t (*fn)(void *param); // Thread function
+ void * param; // Parameter for the thread function
+ void * cxt; // The current thread context.
+ } thread;
+
+typedef struct threadQ {
+ thread *head;
+ thread *tail;
+} threadQ;
+
+static threadQ readyQ; // The list of ready threads
+static threadQ deadQ; // Where we put threads waiting to be deallocated
+static thread * current; // The current running thread
+static thread mainthread; // The main thread context
+
+#if GFX_CPU == GFX_CPU_UNKNOWN
+
+ #include <string.h> // Prototype for memcpy()
+ #include <setjmp.h>
+
+ /**
+ * Some compilers define a _setjmp() and a setjmp().
+ * The difference between them is that setjmp() saves the signal masks.
+ * That is of no use to us so we prefer to use the _setjmp() methods.
+ * If they don't exist compile them to be the standard setjmp() function.
+ * Similarly for longjmp().
+ */
+ #if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
+ #define CXT_SAVE setjmp
+ #else
+ #define CXT_SAVE _setjmp
+ #endif
+ #if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
+ #define CXT_RESTORE longjmp
+ #else
+ #define CXT_RESTORE _longjmp
+ #endif
+
+ // A place to store the main thread context.
+ // All other threads will store the context directly after the thread structure (as part of the stack space).
+ static jmp_buf maincxt;
+
+ /**
+ * There are some compilers we know how they store the jmpbuf. For those
+ * we can use the constant macro definitions. For others we have to "auto-detect".
+ * Auto-detection is hairy and there is no guarantee it will work on all architectures.
+ * For those it doesn't - read the compiler manuals and the library source code to
+ * work out the correct macro values.
+ * You can use the debugger to work out the values for your compiler and put them here.
+ * Defining these macros as constant values makes the system behaviour guaranteed but also
+ * makes your code compiler and cpu architecture dependent. It also saves a heap of code
+ * and a few bytes of RAM.
+ *
+ * MACROS:
+ *
+ * AUTO_DETECT_STACKFRAME TRUE/FALSE - TRUE to auto-detect stack frame structure
+ * STACK_DIR_UP Macro/bool_t - TRUE if the stack grows up instead of down
+ * MASK1 Macro/uint32_t - The 1st mask of jmp_buf elements that need relocation
+ * MASK2 Macro/uint32_t - The 2nd mask of jmp_buf elements that need relocation
+ * STACK_BASE Macro/size_t - The base of the stack frame relative to the local variables
+ * _gfxThreadsInit() Macro/Function - Initialise the scheduler
+ *
+ */
+ #if GFX_COMPILER == GFX_COMPILER_MINGW32
+
+ #define AUTO_DETECT_STACKFRAME FALSE
+ #define STACK_DIR_UP FALSE
+ #define MASK1 0x00000011
+ #define MASK2 0x00000000
+ #define STACK_BASE 12
+ #define _gfxThreadsInit() mainthread.cxt = maincxt
+
+ #else
+
+ // Use auto-detection of the stack frame format
+ // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
+ #define AUTO_DETECT_STACKFRAME TRUE
+ #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
+ #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
+ #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
+ #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
+
+ // The structure for the saved stack frame information
+ typedef struct saveloc {
+ char * localptr;
+ jmp_buf cxt;
+ } saveloc;
+
+ static bool_t stackdirup;
+ static uint32_t jmpmask1;
+ static uint32_t jmpmask2;
+ static size_t stackbase;
+ static saveloc *pframeinfo;
+
+ // These two functions are not static to prevent the compiler removing them as functions
+ void _gfxGetStackState(void) {
+ char *c;
+ pframeinfo->localptr = (char *)&c;
+ CXT_SAVE(pframeinfo->cxt);
+ }
+ void _gfxGetStackStateInFn(void) {
+ pframeinfo++;
+ _gfxGetStackState();
+ pframeinfo--;
+ }
+ static void _gfxThreadsInit(void) {
+ uint32_t i;
+ char ** pout;
+ char ** pin;
+ size_t diff;
+ char * framebase;
+ saveloc tmpsaveloc[2];
+
+ // Create the main thread context
+ mainthread.cxt = maincxt;
+
+ // Allocate a buffer to store our test data
+ pframeinfo = tmpsaveloc;
+
+ // Get details of the stack frame from within a function
+ _gfxGetStackStateInFn();
+
+ // Get details of the stack frame outside the function
+ _gfxGetStackState();
+
+ /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
+ stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
+ pout = (char **)pframeinfo[0].cxt;
+ pin = (char **)pframeinfo[1].cxt;
+ diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
+ framebase = pframeinfo[0].localptr;
+ jmpmask1 = jmpmask2 = 0;
+ for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
+ if ((size_t)(*pout - *pin) == diff) {
+ if (i < 32)
+ jmpmask1 |= 1 << i;
+ else
+ jmpmask2 |= 1 << (i-32);
+
+ if (stackdirup) {
+ if (framebase > *pout)
+ framebase = *pout;
+ } else {
+ if (framebase < *pout)
+ framebase = *pout;
+ }
+ }
+ }
+ stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
+ }
+
+ #endif
+
+ // Move the stack frame and relocate the context data
+ static void _gfxAdjustCxt(thread *t) {
+ char ** s;
+ char * nf;
+ int diff;
+ uint32_t i;
+
+ // Copy the stack frame
+ #if AUTO_DETECT_STACKFRAME
+ if (STACK_DIR_UP) { // Stack grows up
+ nf = (char *)(t) + sizeof(thread) + sizeof(jmp_buf) + stackbase;
+ memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
+ } else { // Stack grows down
+ nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
+ memcpy(nf, &s, stackbase+sizeof(char *));
+ }
+ #elif STACK_DIR_UP
+ // Stack grows up
+ nf = (char *)(t) + sizeof(thread) + sizeof(jmp_buf) + stackbase;
+ memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
+ #else
+ // Stack grows down
+ nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
+ memcpy(nf, &s, stackbase+sizeof(char *));
+ #endif
+
+ // Relocate the context data
+ s = (char **)(t->cxt);
+ diff = nf - (char *)&s;
+
+ // Relocate the elements we know need to be relocated
+ for (i = MASK1; i ; i >>= 1, s++) {
+ if ((i & 1))
+ *s += diff;
+ }
+ #ifdef MASK2
+ s = (char **)(t->cxt)+32;
+ for (i = MASK2; i ; i >>= 1, s++) {
+ if ((i & 1))
+ *s += diff;
+ }
+ #endif
+ }
+ static void _gfxXSwitch(thread *oldt, thread *newt, bool_t doBuildFrame) {
+
+ // Save the old context
+ if (CXT_SAVE(oldt->cxt)) return;
+
+ // Do we need to build a new context?
+ if (doBuildFrame) {
+
+ // Save our existing context as a starting point for the new context
+ newt->cxt = newt+1;
+ if (CXT_SAVE(newt->cxt)) {
+
+ // We are now running the new thread
+
+ // We can't use any of the above function parameters here
+ // as we are on a different stack.
+
+ // Run the users function.
+ gfxThreadExit(current->fn(current->param));
+
+ // We never get here as gfxThreadExit() never returns
+ }
+
+ // Adjust the new context so the stack references are correct
+ _gfxAdjustCxt(newt);
+ }
+
+ // Start the new context
+ CXT_RESTORE(newt->cxt, 1);
+ }
+
+ #define _gfxTaskSwitch(oldt, newt) _gfxXSwitch(oldt, newt, FALSE)
+ #define _gfxStartThread(oldt, newt) _gfxXSwitch(oldt, newt, TRUE)
+
+#elif GFX_CPU == GFX_CPU_CORTEX_M0 || GFX_CPU == GFX_CPU_CORTEX_M1
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t"
+ "mov r4, r8 \n\t"
+ "mov r5, r9 \n\t"
+ "mov r6, r10 \n\t"
+ "mov r7, r11 \n\t"
+ "push {r4, r5, r6, r7} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "pop {r4, r5, r6, r7} \n\t"
+ "mov r8, r4 \n\t"
+ "mov r9, r5 \n\t"
+ "mov r10, r6 \n\t"
+ "mov r11, r7 \n\t"
+ "pop {r4, r5, r6, r7, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t" // save current context
+ "str sp, %[oldtcxt] \n\t" // save context pointer
+ "ldr sp, %[newtcxt] \n\t" // load new context pointer
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#elif GFX_CPU == GFX_CPU_CORTEX_M3 || GFX_CPU == GFX_CPU_CORTEX_M4 || GFX_CPU == GFX_CPU_CORTEX_M7
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #if CORTEX_USE_FPU
+ #warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M? with no hardware floating point support but CORTEX_USE_FPU is TRUE. Try using GFX_CPU_GFX_CPU_CORTEX_M?_FP instead"
+ #endif
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#elif GFX_CPU == GFX_CPU == GFX_CPU_CORTEX_M4_FP || GFX_CPU == GFX_CPU_CORTEX_M7_FP
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11 and floating point
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #if !CORTEX_USE_FPU
+ #warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M?_FP with hardware floating point support but CORTEX_USE_FPU is FALSE. Try using GFX_CPU_GFX_CPU_CORTEX_M? instead"
+ #endif
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "vpush {s16-s31} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "vpop {s16-s31} \n\t"
+ "pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "vpush {s16-s31} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#else
+ #error "GOS Threads: Unsupported Scheduler. Try setting GFX_CPU = GFX_CPU_UNKNOWN"
+#endif
+
+static void Qinit(threadQ * q) {
+ q->head = q->tail = 0;
+}
+
+static void Qadd(threadQ * q, thread *t) {
+ t->next = 0;
+ if (q->head) {
+ q->tail->next = t;
+ q->tail = t;
+ } else
+ q->head = q->tail = t;
+}
+
+static thread *Qpop(threadQ * q) {
+ struct thread * t;
+
+ if (!q->head)
+ return 0;
+ t = q->head;
+ q->head = t->next;
+ return t;
+}
+
+void _gosThreadsInit(void) {
+ Qinit(&readyQ);
+
+ mainthread.next = 0;
+ mainthread.size = sizeof(thread);
+ mainthread.flags = FLG_THD_MAIN;
+ mainthread.fn = 0;
+ mainthread.param = 0;
+
+ _gfxThreadsInit();
+
+ current = &mainthread;
+}
+
+gfxThreadHandle gfxThreadMe(void) {
+ return (gfxThreadHandle)current;
+}
+
+// Check if there are dead processes to deallocate
+static void cleanUpDeadThreads(void) {
+ thread *p;
+
+ while ((p = Qpop(&deadQ)))
+ gfxFree(p);
+}
+
+void gfxYield(void) {
+ thread *me;
+
+ // Clean up zombies
+ cleanUpDeadThreads();
+
+ // Is there another thread to run?
+ if (!readyQ.head)
+ return;
+
+ Qadd(&readyQ, me = current);
+ current = Qpop(&readyQ);
+ _gfxTaskSwitch(me, current);
+}
+
+// This routine is not currently public - but it could be.
+void gfxThreadExit(threadreturn_t ret) {
+ thread *me;
+
+ // Save the results in case someone is waiting
+ me = current;
+ me->param = (void *)ret;
+ me->flags |= FLG_THD_DEAD;
+
+ // Add us to the dead list if we need deallocation as we can't free ourselves.
+ // If someone is waiting on the thread they will do the cleanup.
+ if ((me->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
+ Qadd(&deadQ, me);
+
+ // Set the next thread. Exit if it was the last thread
+ if (!(current = Qpop(&readyQ)))
+ gfxExit();
+
+ // Switch to the new thread
+ _gfxTaskSwitch(me, current);
+
+ // We never get back here as we didn't re-queue ourselves
+}
+
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
+ thread * t;
+ thread * me;
+ (void) prio;
+
+ // Ensure we have a minimum stack size
+ if (stacksz < sizeof(thread)+64) {
+ stacksz = sizeof(thread)+64;
+ stackarea = 0;
+ }
+
+ if (stackarea) {
+ t = (thread *)stackarea;
+ t->flags = 0;
+ } else {
+ t = (thread *)gfxAlloc(stacksz);
+ if (!t)
+ return 0;
+ t->flags = FLG_THD_ALLOC;
+ }
+ t->size = stacksz;
+ t->fn = fn;
+ t->param = param;
+
+ // Add the current thread to the queue because we are starting a new thread.
+ me = current;
+ Qadd(&readyQ, me);
+ current = t;
+
+ _gfxStartThread(me, t);
+
+ // Return the new thread handle
+ return t;
+}
+
+threadreturn_t gfxThreadWait(gfxThreadHandle th) {
+ thread * t;
+
+ t = th;
+ if (t == current)
+ return -1;
+
+ // Mark that we are waiting
+ t->flags |= FLG_THD_WAIT;
+
+ // Wait for the thread to die
+ while(!(t->flags & FLG_THD_DEAD))
+ gfxYield();
+
+ // Unmark
+ t->flags &= ~FLG_THD_WAIT;
+
+ // Clean up resources if needed
+ if (t->flags & FLG_THD_ALLOC)
+ gfxFree(t);
+
+ // Return the status left by the dead process
+ return (threadreturn_t)t->param;
+}
+
+#endif /* GFX_USE_OS_RAW32 */
diff --git a/src/gos/gos_x_threads.h b/src/gos/gos_x_threads.h
new file mode 100644
index 00000000..78c30ac4
--- /dev/null
+++ b/src/gos/gos_x_threads.h
@@ -0,0 +1,103 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This threading implementation supports most 32 bit processors with or without an
+ * underlying operating system. It uses cooperative multi-tasking. Be careful
+ * when writing device drivers not to disturb the assumptions this creates by performing
+ * call-backs from interrupt handlers to uGFX code unless you define the INTERRUPTS_OFF()
+ * and INTERRUPTS_ON() macros.
+ * It still requires some C runtime library support for the setjmp implementation...
+ * setjmp() and longjmp() - for threading
+ * memcpy() - for heap and threading
+ *
+ * You must also define the following routines in your own code so that timing functions will work...
+ * systemticks_t gfxSystemTicks(void);
+ * systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+ */
+#ifndef _GOS_X_THREADS_H
+#define _GOS_X_THREADS_H
+
+#if GOS_NEED_X_THREADS
+
+typedef uint32_t delaytime_t;
+typedef uint32_t systemticks_t;
+typedef short semcount_t;
+typedef int threadreturn_t;
+typedef int threadpriority_t;
+
+#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
+#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
+
+#define TIME_IMMEDIATE 0
+#define TIME_INFINITE ((delaytime_t)-1)
+#define MAX_SEMAPHORE_COUNT 0x7FFF
+#define LOW_PRIORITY 0
+#define NORMAL_PRIORITY 1
+#define HIGH_PRIORITY 2
+
+typedef struct {
+ semcount_t cnt;
+ semcount_t limit;
+} gfxSem;
+
+typedef uint32_t gfxMutex;
+typedef void * gfxThreadHandle;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Required timing functions - supplied by the user or the operating system
+ systemticks_t gfxSystemTicks(void);
+ systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+
+ // Sleep Functions
+ void gfxSleepMilliseconds(delaytime_t ms);
+ void gfxSleepMicroseconds(delaytime_t ms);
+ void gfxYield(void);
+
+ // System Locking
+ void gfxSystemLock(void);
+ void gfxSystemUnlock(void);
+
+ // Mutexes
+ void gfxMutexInit(gfxMutex *pmutex);
+ #define gfxMutexDestroy(pmutex)
+ void gfxMutexEnter(gfxMutex *pmutex);
+ void gfxMutexExit(gfxMutex *pmutex);
+
+ // Semaphores
+ void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
+ #define gfxSemDestroy(psem)
+ bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+ bool_t gfxSemWaitI(gfxSem *psem);
+ void gfxSemSignal(gfxSem *psem);
+ void gfxSemSignalI(gfxSem *psem);
+
+ // Deprecated Semaphore functions (they still work here)
+ #define gfxSemCounter(psem) ((psem)->cnt)
+ #define gfxSemCounterI(psem) ((psem)->cnt)
+
+ // Threads
+ gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
+ #define gfxThreadClose(thread)
+ threadreturn_t gfxThreadWait(gfxThreadHandle thread);
+ gfxThreadHandle gfxThreadMe(void);
+
+ /** The following is not part of the public ugfx API has some operating systems
+ * simply do not provide this capability.
+ * For RAW32 we need it anyway so we might as well declare it here.
+ */
+ void gfxThreadExit(threadreturn_t ret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOS_NEED_X_THREADS */
+#endif /* _GOS_X_THREADS_H */