gadget-chilipepper-plantmon.../main.c
Daniele Lacamera a67219081c Initial commit
2019-03-26 09:28:17 +01:00

426 lines
10 KiB
C

/* (c) Daniele Lacamera 2019
* GPL
*/
#include <unicore-mx/stm32/rcc.h>
#include <unicore-mx/stm32/gpio.h>
#include <unicore-mx/stm32/adc.h>
#include <unicore-mx/stm32/usart.h>
#include <unicore-mx/stm32/fsmc.h>
#include <stdlib.h>
#include <stdint.h>
#include "system.h"
#include "button.h"
#include "img/chili.h"
void usart1_init(void);
void usart1_puts(char *s);
#define FONT_HEIGHT 8
#define FONT_WIDTH 8
#define BGCOLOR (0xfdff)
extern const unsigned char fb_font[256][FONT_WIDTH];
#define BUTTON_DEBOUNCE_TIME 100
/* Board pins:
* KEYA = PC13
* KEYB = PB2
* LED1 = PB0
* LED2 = PB1
*/
/* ADC pins:
* PA3: LM35 temp
* PA2: Light sensor
* PA1: soil sensor
*/
#define TFT_FSMC_ADDRESS_SETUP 9
#define TFT_FSMC_ADDRESS_HOLD 1
#define TFT_FSMC_DATA_SETUP 7
#define TFT_FSMC_BUS_TURNAROUND 0
#define TFT_FSMC_CLKDIVISION 0
#define TFT_FSMC_DATALATENCY 0
#define TFT_FSMC_ACCESS_MODE 0
#define TFT_FSMC_BANK 0
#define TFT_FSMC_DATAWIDHT_16 0x10
#define TFT_FSMC_WRITE_ENABLE 0x1000
#define FSMC_BTCR(X) (((volatile uint32_t *)(FSMC_BASE)))[X]
#define FSMC_E_BWTR(X) (((volatile uint32_t *)(FSMC_BASE + 0x104)))[X]
#define TFT_REG (*((volatile uint16_t *) 0x60000000))
#define TFT_RAM (*((volatile uint16_t *) 0x60020000))
static void TFT_CMD(uint16_t reg, uint16_t val) {
TFT_REG = (reg);
TFT_RAM = (val);
}
#define tft_init_sequence() { \
TFT_CMD(0x0007, 0x0021); \
TFT_CMD(0x0000, 0x0001); \
TFT_CMD(0x0007, 0x0023); \
TFT_CMD(0x0010, 0x0000); \
TFT_CMD(0x0007, 0x0033); \
TFT_CMD(0x0011, 0x6800); \
TFT_CMD(0x0002, 0x0600); \
TFT_CMD(0x0012, 0x6CEB); \
TFT_CMD(0x0003, 0xA8A4); \
TFT_CMD(0x000C, 0x0000); \
TFT_CMD(0x000D, 0x080C); \
TFT_CMD(0x000E, 0x2B00); \
TFT_CMD(0x001E, 0x00B0); \
TFT_CMD(0x0001, 0x2B3F); \
TFT_CMD(0x0005, 0x0000); \
TFT_CMD(0x0006, 0x0000); \
TFT_CMD(0x0016, 0xEF1C); \
TFT_CMD(0x0017, 0x0103); \
TFT_CMD(0x000B, 0x0000); \
TFT_CMD(0x000F, 0x0000); \
TFT_CMD(0x0041, 0x0000); \
TFT_CMD(0x0042, 0x0000); \
TFT_CMD(0x0048, 0x0000); \
TFT_CMD(0x0049, 0x013F); \
TFT_CMD(0x004A, 0x0000); \
TFT_CMD(0x004B, 0x0000); \
TFT_CMD(0x0044, 0xEF00); \
TFT_CMD(0x0045, 0x0000); \
TFT_CMD(0x0046, 0x013F); \
TFT_CMD(0x0030, 0x0707); \
TFT_CMD(0x0031, 0x0204); \
TFT_CMD(0x0032, 0x0204); \
TFT_CMD(0x0033, 0x0502); \
TFT_CMD(0x0034, 0x0507); \
TFT_CMD(0x0035, 0x0204); \
TFT_CMD(0x0036, 0x0204); \
TFT_CMD(0x0037, 0x0502); \
TFT_CMD(0x003A, 0x0302); \
TFT_CMD(0x002F, 0x12BE); \
TFT_CMD(0x003B, 0x0302); \
TFT_CMD(0x0023, 0x0000); \
TFT_CMD(0x0024, 0x0000); \
TFT_CMD(0x0025, 0x8000); \
TFT_CMD(0x004e, 0x0000); \
TFT_CMD(0x004f, 0x0000); \
}
#define TFT_MAX_X 320
#define TFT_MAX_Y 240
#define TFT_GO(x,y) { \
TFT_CMD(0x004E, x); \
TFT_CMD(0x004F, y); \
TFT_REG = 0x22; \
}
void set_pixel(uint16_t x, uint16_t y, uint16_t val)
{
TFT_GO(y, 319 - x);
TFT_REG = 0x22;
TFT_RAM = val;
}
void text_at(uint16_t color, uint32_t x, uint32_t y, char *text)
{
uint32_t i, j;
char fc;
const uint8_t *render;
int nc = 0;
while(text[0]) {
fc = text[0];
render = fb_font[(int)fc];
for (i = 0; i < FONT_HEIGHT; i++) {
for (j = 0; j < FONT_WIDTH; j++) {
int right_shift = (FONT_HEIGHT - 1) - j;
if (render[i] & (1 << (7 - j))) {
set_pixel(x + j + nc * FONT_WIDTH, y + i, color);
}
}
}
nc++;
text++;
}
}
void draw_ppm(const uint8_t *buf, uint32_t len, uint32_t w, uint16_t x, uint16_t y)
{
int i, r = 0;
uint32_t h = (len >> 1) / w;
if (((x + w) > TFT_MAX_X) || ((y + h) > TFT_MAX_Y))
return;
for (i = 0; i < chili_ppm_len;) {
int j = 0;
for (j = 0; j < chili_ppm_width; j++) {
set_pixel(x + j, y + r, *(uint16_t *)(chili_ppm + i));
i+=2;
}
r++;
}
}
void fill_area(uint16_t val, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
int i, r = 0;
if (((x + w) > TFT_MAX_X) || ((y + h) > TFT_MAX_Y))
return;
for (i = 0; i < w * h;) {
int j = 0;
for (j = 0; j < w; j++) {
set_pixel(x + j, y + r, val);
i+=2;
}
r++;
}
}
static void tft_init(void)
{
int i;
volatile uint16_t id;
rcc_periph_clock_enable(RCC_FSMC);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOD);
rcc_periph_clock_enable(RCC_GPIOE);
gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
GPIO0 | GPIO1 | GPIO4 | GPIO5 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO14 | GPIO15 );
gpio_set_mode(GPIOE, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
GPIO3 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15);
/* B5 is backlight */
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO5);
gpio_set(GPIOB, GPIO5);
FSMC_BTCR(0) = TFT_FSMC_DATAWIDHT_16 | TFT_FSMC_WRITE_ENABLE;
FSMC_BTCR(1) = TFT_FSMC_ADDRESS_SETUP |
(TFT_FSMC_ADDRESS_HOLD << 4) |
(TFT_FSMC_DATA_SETUP << 8) |
(TFT_FSMC_BUS_TURNAROUND << 16) |
(TFT_FSMC_CLKDIVISION << 20) |
(TFT_FSMC_DATALATENCY << 24) |
TFT_FSMC_ACCESS_MODE;
FSMC_BTCR(0) |= 1;
FSMC_E_BWTR(0) = 0x0FFFFFFF;
TFT_REG = 0x00;
id = TFT_RAM;
tft_init_sequence();
/* Erase screen */
TFT_GO(0,0);
for (i = 0; i < TFT_MAX_X * TFT_MAX_Y; i++)
TFT_RAM = BGCOLOR;
/* Chili */
draw_ppm(chili_ppm, chili_ppm_len, chili_ppm_width, 0, TFT_MAX_Y - 160);
}
static void adc_setup(void)
{
int i;
rcc_periph_clock_enable(RCC_ADC1);
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, GPIO3|GPIO1|GPIO2);
adc_power_off(ADC1);
adc_disable_scan_mode(ADC1);
adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC);
adc_power_on(ADC1);
for (i = 0; i < 80000; i++)
;
adc_reset_calibration(ADC1);
adc_calibration(ADC1);
}
static uint16_t adc_read(uint8_t channel, int samples)
{
uint8_t seq[2];
uint32_t sum = 0;
uint32_t i,waiting;
seq[0] = channel;
ADC_CR2(ADC1) |= ADC_CR2_ADON;
for (i = 0 ; i < samples; i++) {
adc_set_regular_sequence(ADC1, 1, seq);
ADC_CR2(ADC1) |= ADC_CR2_ADON;
while (!adc_eoc(ADC1))
;
sum += adc_read_regular(ADC1);
}
return (uint16_t)(sum / samples);
}
static uint16_t loop_read(uint8_t channel)
{
return adc_read(channel, 8);
}
static uint16_t temp_read(void)
{
return loop_read(3);
}
static uint16_t cputemp_read(void)
{
return loop_read(16);
}
static uint16_t light_read(void)
{
return loop_read(2);
}
static uint16_t soil_read(void)
{
return loop_read(1);
}
static int print_int(int value, char *str)
{
int8_t i;
uint8_t nr_digits = 0;
char local_buffer[25];
char *buffer;
int x = 1000 * 1000 * 1000;
int started = 0;
if (str)
buffer = str;
else
buffer = local_buffer;
if (value < 0) {
buffer[0] = '-';
value = value * -1;
nr_digits++;
}
while (1) {
if (started || (x == 1) || ((value / x) > 0)) {
buffer[nr_digits++] = '0' + value / x;
started = 1;
}
if (x == 1)
break;
value %= x;
x /= 10;
}
buffer[nr_digits] = '\0';
if (str == NULL)
usart1_puts(buffer);
return nr_digits;
}
void main(void) {
volatile int button_channel = 0;
uint32_t start_pressed = 0;
uint32_t switchtime = 0;
uint16_t light, temp= 0, soil = 0, cputemp;
int i;
char str[100];
rcc_clock_setup_in_hse_8mhz_out_72mhz();
//button_setup();
//button_start_read();
adc_setup();
usart1_init();
tft_init();
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO0 | GPIO1);
gpio_set(GPIOB, GPIO0 | GPIO1);
usart1_puts("\e[2J"); // clear screen on terminal
usart1_puts("\e[0;0H"); // home cursor
gpio_clear(GPIOB, GPIO0);
while(1) {
uint32_t temp_integer = 0;
uint32_t temp_fractions = 0;
int half_degree = 0;
char tmp_text[10];
int tlen = 0;
uint16_t light_percent, soil_percent;
temp = temp_read();
temp_integer = (temp * 330);
temp_fractions = temp_integer % 4096;
temp_integer >>= 12;
if (temp_fractions > 1024 && temp_fractions < 3072)
half_degree = 1;
if (temp_fractions >= 3072)
temp_integer++;
soil = soil_read();
light = light_read();
usart1_puts("Temperature: ");
print_int(temp_integer, NULL);
if (half_degree)
usart1_puts(".5");
/* Temperature on screen */
fill_area(BGCOLOR, 260, 40, 60, 20);
text_at(0, 120, 40, "Temperature ");
tlen = print_int(temp_integer, tmp_text);
text_at(0, 260, 40, tmp_text);
if (half_degree)
text_at(0, 260 + 8 * tlen, 40, ".5");
usart1_puts(", Light: ");
print_int(light, NULL);
light_percent = (100 * light) >> 12;
fill_area(BGCOLOR, 260, 70, 60, 20);
text_at(0, 120, 70, "Light exposure ");
tlen = print_int(light_percent, tmp_text);
text_at(0, 260, 70, tmp_text);
text_at(0, 280, 70, "/100");
usart1_puts(", Soil: ");
print_int(soil, NULL);
usart1_puts("\r\n");
soil_percent = (100 * soil) >> 12;
fill_area(BGCOLOR, 260, 100, 60, 20);
text_at(0, 120, 100, "Soil moisture ");
tlen = print_int(soil_percent, tmp_text);
text_at(0, 260, 100, tmp_text);
text_at(0, 280, 100, "/100");
for (i = 0; i < 1440000; i++)
;
gpio_toggle(GPIOB, GPIO1);
if (button_press_pending) {
button_press_pending = 0;
}
}
}