add simple work with fonts (too small for this screen), still have some bugs with sprites in lower right corner

This commit is contained in:
Edward Emelianov 2023-05-11 00:36:10 +03:00
parent eda7d9127a
commit d88de360d0
16 changed files with 4917 additions and 64 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,786 @@
/*
* This file is part of the nitrogen project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// numbers and base symbols up to Z
// this file should be included JUST ONCE!
// only in fonts.c
#define FONTNUMB8BYTES 10
#define FONTNUMB8HEIGHT 10
#define FONTNUMB8BASELINE 2
// this array shows position of every koi8-r symbol in font10_table
const uint8_t fontNumb8_encoding[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0..31
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
/*20*/1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, // 47
/*30*/2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 29, 30, 31, 32, 33, 34, // 63
/*40*/35, 12, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 13, // 79
/*50*/49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, // 95
/*60*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 111
/*70*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 127
/*80*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 143
/*90*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 159
/*A0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 175
/*B0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 191
/*C0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 207
/*D0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 223
/*E0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 239
/*F0*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 255
};
const uint8_t fontNumb8_table[] = {
// 0 0x00 - empty
0,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
// 1 0x20 - ' '
4,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
// 2 0x30 - '0'
6,
_XXX____,
XX_XX___,
X___X___,
X___X___,
X___X___,
X___X___,
XX_XX___,
_XXX____,
________,
________,
// 3 0x31 - '1'
6,
_XX_____,
X_X_____,
__X_____,
__X_____,
__X_____,
__X_____,
__X_____,
XXXXX___,
________,
________,
// 4 0x32 - '2'
6,
_XXX____,
X___X___,
____X___,
____X___,
___X____,
__X_____,
_X______,
XXXXX___,
________,
________,
// 5 0x33 - '3'
6,
XXXX____,
____X___,
____X___,
_XXX____,
____X___,
____X___,
____X___,
XXXX____,
________,
________,
// 6 0x34 - '4'
7,
___XX___,
___XX___,
__X_X___,
_X__X___,
_X__X___,
XXXXXX__,
____X___,
____X___,
________,
________,
// 7 0x35 - '5'
5,
XXXX____,
X_______,
X_______,
XXX_____,
___X____,
___X____,
___X____,
XXX_____,
________,
________,
// 8 0x36 - '6'
6,
_XXX____,
X___X___,
X_______,
XXXX____,
X___X___,
X___X___,
X___X___,
_XXX____,
________,
________,
// 9 0x37 - '7'
5,
XXXX____,
___X____,
__X_____,
__X_____,
__X_____,
_X______,
_X______,
_X______,
________,
________,
// 10 0x38 - '8'
6,
_XXX____,
X___X___,
X___X___,
_XXX____,
X___X___,
X___X___,
X___X___,
_XXX____,
________,
________,
// 11 0x39 - '9'
6,
_XXX____,
X___X___,
X___X___,
X___X___,
_XXXX___,
____X___,
X___X___,
_XXX____,
________,
________,
// 12 0x41 - 'A'
6,
__X_____,
_X_X____,
_X_X____,
_X_X____,
X___X___,
XXXXX___,
X___X___,
X___X___,
________,
________,
// 13 0x4f - 'O'
7,
__XX____,
_X__X___,
X____X__,
X____X__,
X____X__,
X____X__,
_X__X___,
__XX____,
________,
________,
// 14 0x21 - '!'
2,
X_______,
X_______,
X_______,
X_______,
X_______,
X_______,
________,
X_______,
________,
________,
// 15 0x22 - '"'
4,
________,
X_X_____,
X_X_____,
X_X_____,
________,
________,
________,
________,
________,
________,
// 16 0x23 - '#'
7,
________,
____X_X_,
___X_X__,
XXXXXXX_,
__X_X___,
XXXXXXX_,
_X_X____,
X_X_____,
________,
________,
// 17 0x24 - '$'
6,
__X_____,
_XXX____,
X_X_X___,
X_X_____,
_XXX____,
__X_X___,
X_X_X___,
XXXX____,
__X_____,
________,
// 18 0x25 - '%'
8,
________,
_XX___X_,
X__X_X__,
_XX_X___,
___X____,
__X_XX__,
_X_X__X_,
X___XX__,
________,
________,
// 19 0x26 - '&'
7,
________,
_X______,
X_X_____,
X_X_____,
_X__XX__,
X_XXX___,
X__X____,
_XX_XX__,
________,
________,
// 20 0x27 - '''
2,
________,
X_______,
X_______,
X_______,
________,
________,
________,
________,
________,
________,
// 21 0x28 - '('
4,
__XX____,
_X______,
X_______,
X_______,
X_______,
X_______,
X_______,
_X______,
__XX____,
________,
// 22 0x29 - ')'
4,
XX______,
__X_____,
___X____,
___X____,
___X____,
___X____,
___X____,
__X_____,
XX______,
________,
// 23 0x2A - '*'
6,
________,
________,
__X_____,
XXXXX___,
_XXX____,
X___X___,
________,
________,
________,
________,
// 24 0x2B - '+'
6,
________,
________,
__X_____,
__X_____,
XXXXX___,
__X_____,
__X_____,
________,
________,
________,
// 25 0x2C - ','
3,
________,
________,
________,
________,
________,
________,
XX______,
_X______,
X_______,
________,
// 26 0x2D - '-'
6,
________,
________,
________,
________,
XXXXX___,
________,
________,
________,
________,
________,
// 27 0x2E - '.'
3,
________,
________,
________,
________,
________,
________,
XX______,
XX______,
________,
________,
// 28 0x2F - '/'
6,
____X___,
___X____,
___X____,
__X_____,
__X_____,
_X______,
_X______,
_X______,
X_______,
________,
// 29 0x3A - ':'
3,
________,
________,
XX______,
XX______,
________,
XX______,
XX______,
________,
________,
________,
// 30 0x3B - ';'
3,
________,
________,
________,
XX______,
XX______,
________,
XX______,
_X______,
X_______,
________,
// 31 0x3C - '<'
4,
________,
________,
__X_____,
_X______,
X_______,
_X______,
__X_____,
________,
________,
________,
// 32 0x3D - '='
5,
________,
________,
________,
XXXX____,
________,
XXXX____,
________,
________,
________,
________,
// 33 0x3E - '>'
4,
________,
________,
X_______,
_X______,
__X_____,
_X______,
X_______,
________,
________,
________,
// 34 0x3F - '?'
5,
_XX_____,
X__X____,
___X____,
__X_____,
_X______,
_X______,
________,
_X______,
________,
________,
// 35 0x40 - '@'
8,
___XXX__,
__X__X__,
_X_XXXX_,
X__X_XX_,
X_X_X_X_,
X_X_X_X_,
X__X_X__,
_X______,
__XXXX__,
________,
// 36 0x42 - 'B'
6,
XXX_____,
X__X____,
X_X_____,
XXXX____,
X___X___,
X___X___,
X___X___,
XXXX____,
________,
________,
// 37 0x43 - 'C'
7,
__XXX___,
_X___X__,
X_______,
X_______,
X_______,
X_______,
_X___X__,
__XXX___,
________,
________,
// 38 0x44 - 'D'
6,
XXX_____,
X__X____,
X___X___,
X___X___,
X___X___,
X___X___,
X__X____,
XXX_____,
________,
________,
// 39 0x45 - 'E'
6,
XXXXX___,
X_______,
X_______,
XXX_____,
X_______,
X_______,
X___X___,
XXXXX___,
________,
________,
// 40 0x46 - 'F'
6,
XXXXX___,
X___X___,
X_______,
X_______,
XXX_____,
X_______,
X_______,
X_______,
________,
________,
// 41 0x47 - 'G'
7,
__XXX___,
_X___X__,
X_______,
X_______,
X_______,
X__XXX__,
_X___X__,
__XXX___,
________,
________,
// 42 0x48 - 'H'
6,
X___X___,
X___X___,
X___X___,
XXXXX___,
X___X___,
X___X___,
X___X___,
X___X___,
________,
________,
// 43 0x49 - 'I'
4,
XXX_____,
_X______,
_X______,
_X______,
_X______,
_X______,
_X______,
XXX_____,
________,
________,
// 44 0x4A - 'J'
5,
XXXX____,
X__X____,
___X____,
___X____,
___X____,
___X____,
X_XX____,
_X______,
________,
________,
// 45 0x4B - 'K'
6,
X___X___,
X__X____,
X_X_____,
XXX_____,
X__X____,
X__X____,
X___X___,
X___X___,
________,
________,
// 46 0x4C - 'L'
6,
X_______,
X_______,
X_______,
X_______,
X_______,
X_______,
X___X___,
XXXXX___,
________,
________,
// 47 0x4D - 'M'
8,
X_____X_,
XX___XX_,
X_X_X_X_,
X_X_X_X_,
X__X__X_,
X_____X_,
X_____X_,
X_____X_,
________,
________,
// 48 0x4E - 'N'
6,
X___X___,
XX__X___,
XX__X___,
X_X_X___,
X_X_X___,
X__XX___,
X__XX___,
X___X___,
________,
________,
// 49 0x50 - 'P'
6,
XXXX____,
X__XX___,
X___X___,
X__XX___,
XXXX____,
X_______,
X_______,
X_______,
________,
________,
// 50 0x51 - 'Q'
7,
__XX____,
_X__X___,
X____X__,
X____X__,
X____X__,
X____X__,
_X_XX___,
__XX____,
___XXX__,
________,
// 51 0x52 - 'R'
6,
XXXX____,
X__XX___,
X___X___,
X__XX___,
XXXX____,
X_X_____,
X__X____,
X__XX___,
________,
________,
// 52 0x53 - 'S'
6,
_XX_____,
X__X____,
X_______,
_XX_____,
__XX____,
____X___,
XX_XX___,
_XXX____,
________,
________,
// 53 0x54 - 'T'
6,
XXXXX___,
__X_____,
__X_____,
__X_____,
__X_____,
__X_____,
__X_____,
__X_____,
________,
________,
// 54 0x55 - 'U'
7,
X____X__,
X____X__,
X____X__,
X____X__,
X____X__,
X____X__,
_X__X___,
__XX____,
________,
________,
// 55 0x56 - 'V'
6,
X___X___,
X___X___,
X___X___,
X___X___,
X___X___,
_X_X____,
_X_X____,
__X_____,
________,
________,
// 56 0x57 - 'W'
8,
X_____X_,
X_____X_,
X_____X_,
X__X__X_,
X__X__X_,
_X_X_X__,
_X_X_X__,
__X_X___,
________,
________,
// 57 0x58 - 'X'
6,
X___X___,
X___X___,
_X_X____,
_X_X____,
__X_____,
_X_X____,
X___X___,
X___X___,
________,
________,
// 58 0x59 - 'Y'
6,
X___X___,
X___X___,
X___X___,
_X_X____,
_XXX____,
__X_____,
__X_____,
__X_____,
________,
________,
// 59 0x5A - 'Z'
6,
XXXXX___,
____X___,
___X____,
__X_____,
__X_____,
_X______,
X_______,
XXXXX___,
________,
________,
};
#if 0
// 14 0x21 - '!'
0,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
________,
#endif

View File

@ -0,0 +1,325 @@
/*
* This file is part of the TETRIS project.
* Copyright 2019 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include "fonts.h"
/* Bash-script to generate the symbols
#!/bin/bash
function bits(){
Ans=""
for x in $(seq 7 -1 0); do
B=$((1<<$x))
if [ $(($1&$B)) -ne 0 ]; then Ans="${Ans}X"
else Ans="${Ans}_"
fi
done
echo $Ans
}
for x in $(seq 0 255); do
printf "#define $(bits $x)\t0x%02x\n" $x
done
*/
#define ________ 0x00
#define _______X 0x01
#define ______X_ 0x02
#define ______XX 0x03
#define _____X__ 0x04
#define _____X_X 0x05
#define _____XX_ 0x06
#define _____XXX 0x07
#define ____X___ 0x08
#define ____X__X 0x09
#define ____X_X_ 0x0a
#define ____X_XX 0x0b
#define ____XX__ 0x0c
#define ____XX_X 0x0d
#define ____XXX_ 0x0e
#define ____XXXX 0x0f
#define ___X____ 0x10
#define ___X___X 0x11
#define ___X__X_ 0x12
#define ___X__XX 0x13
#define ___X_X__ 0x14
#define ___X_X_X 0x15
#define ___X_XX_ 0x16
#define ___X_XXX 0x17
#define ___XX___ 0x18
#define ___XX__X 0x19
#define ___XX_X_ 0x1a
#define ___XX_XX 0x1b
#define ___XXX__ 0x1c
#define ___XXX_X 0x1d
#define ___XXXX_ 0x1e
#define ___XXXXX 0x1f
#define __X_____ 0x20
#define __X____X 0x21
#define __X___X_ 0x22
#define __X___XX 0x23
#define __X__X__ 0x24
#define __X__X_X 0x25
#define __X__XX_ 0x26
#define __X__XXX 0x27
#define __X_X___ 0x28
#define __X_X__X 0x29
#define __X_X_X_ 0x2a
#define __X_X_XX 0x2b
#define __X_XX__ 0x2c
#define __X_XX_X 0x2d
#define __X_XXX_ 0x2e
#define __X_XXXX 0x2f
#define __XX____ 0x30
#define __XX___X 0x31
#define __XX__X_ 0x32
#define __XX__XX 0x33
#define __XX_X__ 0x34
#define __XX_X_X 0x35
#define __XX_XX_ 0x36
#define __XX_XXX 0x37
#define __XXX___ 0x38
#define __XXX__X 0x39
#define __XXX_X_ 0x3a
#define __XXX_XX 0x3b
#define __XXXX__ 0x3c
#define __XXXX_X 0x3d
#define __XXXXX_ 0x3e
#define __XXXXXX 0x3f
#define _X______ 0x40
#define _X_____X 0x41
#define _X____X_ 0x42
#define _X____XX 0x43
#define _X___X__ 0x44
#define _X___X_X 0x45
#define _X___XX_ 0x46
#define _X___XXX 0x47
#define _X__X___ 0x48
#define _X__X__X 0x49
#define _X__X_X_ 0x4a
#define _X__X_XX 0x4b
#define _X__XX__ 0x4c
#define _X__XX_X 0x4d
#define _X__XXX_ 0x4e
#define _X__XXXX 0x4f
#define _X_X____ 0x50
#define _X_X___X 0x51
#define _X_X__X_ 0x52
#define _X_X__XX 0x53
#define _X_X_X__ 0x54
#define _X_X_X_X 0x55
#define _X_X_XX_ 0x56
#define _X_X_XXX 0x57
#define _X_XX___ 0x58
#define _X_XX__X 0x59
#define _X_XX_X_ 0x5a
#define _X_XX_XX 0x5b
#define _X_XXX__ 0x5c
#define _X_XXX_X 0x5d
#define _X_XXXX_ 0x5e
#define _X_XXXXX 0x5f
#define _XX_____ 0x60
#define _XX____X 0x61
#define _XX___X_ 0x62
#define _XX___XX 0x63
#define _XX__X__ 0x64
#define _XX__X_X 0x65
#define _XX__XX_ 0x66
#define _XX__XXX 0x67
#define _XX_X___ 0x68
#define _XX_X__X 0x69
#define _XX_X_X_ 0x6a
#define _XX_X_XX 0x6b
#define _XX_XX__ 0x6c
#define _XX_XX_X 0x6d
#define _XX_XXX_ 0x6e
#define _XX_XXXX 0x6f
#define _XXX____ 0x70
#define _XXX___X 0x71
#define _XXX__X_ 0x72
#define _XXX__XX 0x73
#define _XXX_X__ 0x74
#define _XXX_X_X 0x75
#define _XXX_XX_ 0x76
#define _XXX_XXX 0x77
#define _XXXX___ 0x78
#define _XXXX__X 0x79
#define _XXXX_X_ 0x7a
#define _XXXX_XX 0x7b
#define _XXXXX__ 0x7c
#define _XXXXX_X 0x7d
#define _XXXXXX_ 0x7e
#define _XXXXXXX 0x7f
#define X_______ 0x80
#define X______X 0x81
#define X_____X_ 0x82
#define X_____XX 0x83
#define X____X__ 0x84
#define X____X_X 0x85
#define X____XX_ 0x86
#define X____XXX 0x87
#define X___X___ 0x88
#define X___X__X 0x89
#define X___X_X_ 0x8a
#define X___X_XX 0x8b
#define X___XX__ 0x8c
#define X___XX_X 0x8d
#define X___XXX_ 0x8e
#define X___XXXX 0x8f
#define X__X____ 0x90
#define X__X___X 0x91
#define X__X__X_ 0x92
#define X__X__XX 0x93
#define X__X_X__ 0x94
#define X__X_X_X 0x95
#define X__X_XX_ 0x96
#define X__X_XXX 0x97
#define X__XX___ 0x98
#define X__XX__X 0x99
#define X__XX_X_ 0x9a
#define X__XX_XX 0x9b
#define X__XXX__ 0x9c
#define X__XXX_X 0x9d
#define X__XXXX_ 0x9e
#define X__XXXXX 0x9f
#define X_X_____ 0xa0
#define X_X____X 0xa1
#define X_X___X_ 0xa2
#define X_X___XX 0xa3
#define X_X__X__ 0xa4
#define X_X__X_X 0xa5
#define X_X__XX_ 0xa6
#define X_X__XXX 0xa7
#define X_X_X___ 0xa8
#define X_X_X__X 0xa9
#define X_X_X_X_ 0xaa
#define X_X_X_XX 0xab
#define X_X_XX__ 0xac
#define X_X_XX_X 0xad
#define X_X_XXX_ 0xae
#define X_X_XXXX 0xaf
#define X_XX____ 0xb0
#define X_XX___X 0xb1
#define X_XX__X_ 0xb2
#define X_XX__XX 0xb3
#define X_XX_X__ 0xb4
#define X_XX_X_X 0xb5
#define X_XX_XX_ 0xb6
#define X_XX_XXX 0xb7
#define X_XXX___ 0xb8
#define X_XXX__X 0xb9
#define X_XXX_X_ 0xba
#define X_XXX_XX 0xbb
#define X_XXXX__ 0xbc
#define X_XXXX_X 0xbd
#define X_XXXXX_ 0xbe
#define X_XXXXXX 0xbf
#define XX______ 0xc0
#define XX_____X 0xc1
#define XX____X_ 0xc2
#define XX____XX 0xc3
#define XX___X__ 0xc4
#define XX___X_X 0xc5
#define XX___XX_ 0xc6
#define XX___XXX 0xc7
#define XX__X___ 0xc8
#define XX__X__X 0xc9
#define XX__X_X_ 0xca
#define XX__X_XX 0xcb
#define XX__XX__ 0xcc
#define XX__XX_X 0xcd
#define XX__XXX_ 0xce
#define XX__XXXX 0xcf
#define XX_X____ 0xd0
#define XX_X___X 0xd1
#define XX_X__X_ 0xd2
#define XX_X__XX 0xd3
#define XX_X_X__ 0xd4
#define XX_X_X_X 0xd5
#define XX_X_XX_ 0xd6
#define XX_X_XXX 0xd7
#define XX_XX___ 0xd8
#define XX_XX__X 0xd9
#define XX_XX_X_ 0xda
#define XX_XX_XX 0xdb
#define XX_XXX__ 0xdc
#define XX_XXX_X 0xdd
#define XX_XXXX_ 0xde
#define XX_XXXXX 0xdf
#define XXX_____ 0xe0
#define XXX____X 0xe1
#define XXX___X_ 0xe2
#define XXX___XX 0xe3
#define XXX__X__ 0xe4
#define XXX__X_X 0xe5
#define XXX__XX_ 0xe6
#define XXX__XXX 0xe7
#define XXX_X___ 0xe8
#define XXX_X__X 0xe9
#define XXX_X_X_ 0xea
#define XXX_X_XX 0xeb
#define XXX_XX__ 0xec
#define XXX_XX_X 0xed
#define XXX_XXX_ 0xee
#define XXX_XXXX 0xef
#define XXXX____ 0xf0
#define XXXX___X 0xf1
#define XXXX__X_ 0xf2
#define XXXX__XX 0xf3
#define XXXX_X__ 0xf4
#define XXXX_X_X 0xf5
#define XXXX_XX_ 0xf6
#define XXXX_XXX 0xf7
#define XXXXX___ 0xf8
#define XXXXX__X 0xf9
#define XXXXX_X_ 0xfa
#define XXXXX_XX 0xfb
#define XXXXXX__ 0xfc
#define XXXXXX_X 0xfd
#define XXXXXXX_ 0xfe
#define XXXXXXXX 0xff
// here are fonts themself
#include "font14.h"
#include "fontNumb8.h"
static const afont FONTS[] = {
[FONT14] = {font14_table, font14_encoding, FONT14HEIGHT, FONT14BYTES, FONT14BASELINE},
[FONTN8] = {fontNumb8_table, fontNumb8_encoding, FONTNUMB8HEIGHT, FONTNUMB8BYTES, FONTNUMB8BASELINE},
};
const afont *curfont = &FONTS[FONT14];
/**
* @brief choose_font - font selector
* @param newfont - font to choose
* @return 0 if all OK
*/
int choose_font(font_t newfont){
if(newfont >= FONT_T_MAX || newfont <= FONT_T_MIN) return 1;
curfont = &FONTS[newfont];
return 0;
}
const uint8_t *font_char(uint8_t Char){
uint8_t idx = curfont->enctable[Char];
if(!idx) return NULL; // no this character in font
return &(curfont->font[idx*(curfont->bytes+1)]);
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of the nitrogen project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
// type for font choosing
typedef enum{
FONT_T_MIN = -1, // no fonts <= this
FONT14, // 16x16, font height near 14px
FONTN8, // numbers and 'A'..'Z', height 8px
FONT_T_MAX // no fonts >= this
} font_t;
int choose_font(font_t newfont);
const uint8_t *font_char(uint8_t Char);
typedef struct{
const uint8_t *font; // font inself
const uint8_t *enctable; // font encoding table
uint8_t height; // full font matrix height
uint8_t bytes; // amount of bytes in font matrix
uint8_t baseline; // baseline position (coordinate from bottom line)
} afont;
extern const afont *curfont;

View File

@ -136,7 +136,6 @@ void hw_setup(){
RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
gpio_setup(); gpio_setup();
i2c_setup(LOW_SPEED); i2c_setup(LOW_SPEED);
spi_setup();
pwm_setup(); pwm_setup();
#ifndef EBUG #ifndef EBUG
iwdg_setup(); iwdg_setup();

View File

@ -24,9 +24,13 @@
#endif #endif
#include "usb.h" #include "usb.h"
#include <string.h> // bzero
// color buffer for DMA translations (2 lines)
uint16_t colorbuf[COLORBUFSZ];
static const uint8_t initcmd[] = { static const uint8_t initcmd[] = {
ILI9341_SWRESET, 0xff, // reset and wait a lot ILI9341_SWRESET, 0xff, // reset and wait a lot
//0xEF, 3, 0x03, 0x80, 0x02, // WTF?
ILI9341_POWCTLA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, // default ILI9341_POWCTLA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, // default
ILI9341_POWCTLB, 3, 0x00, 0xC1, 0x30, // PC/EQ for power saving ILI9341_POWCTLB, 3, 0x00, 0xC1, 0x30, // PC/EQ for power saving
ILI9341_DRVTCTLA1, 3, 0x85, 0x00, 0x78, // EQ timimg ILI9341_DRVTCTLA1, 3, 0x85, 0x00, 0x78, // EQ timimg
@ -48,7 +52,7 @@ static const uint8_t initcmd[] = {
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
ILI9341_NEGGAMCOR, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma ILI9341_NEGGAMCOR, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
ILI9341_SLPOUT, 0x8a, // Exit Sleep ILI9341_SLPOUT, 0x8a, // Exit Sleep and wait 10ms
ILI9341_NORON, 0x80, // Normal display mode ON ILI9341_NORON, 0x80, // Normal display mode ON
ILI9341_DISPON, 0x80, // Display on ILI9341_DISPON, 0x80, // Display on
0x00 // End of list 0x00 // End of list
@ -70,6 +74,8 @@ int ili9341_init(){
if(!ili9341_writereg(reg, ptr, N)) return 0; if(!ili9341_writereg(reg, ptr, N)) return 0;
ptr += N; ptr += N;
} }
if(!ili9341_setcol(0, SCRNW-1)) return 0;
if(!ili9341_setrow(0, SCRNH-1)) return 0;
return 1; return 1;
} }
@ -174,14 +180,47 @@ int ili9341_writecmd(uint8_t cmd){
return r; return r;
} }
// write data // read/write data over DMA
int ili9341_writedata(const uint8_t *data, uint32_t N){ static int dmardwr(uint8_t *out, uint8_t *in, uint32_t N){
if(!out || !N) return 0;
if(in) bzero(out, N);
SCRN_Data(); SCRN_Data();
SCRN_RST_set(0); SCRN_RST_set(0);
uint32_t r = 0;
do{
if(!spi_write_dma((const uint8_t*)out, in, N)) break;
if(!spi_waitbsy()) break;
uint32_t T = Tms;
while(Tms - T < 100 && spi_status != SPI_READY);
if(spi_status != SPI_READY) break;
if(in){if(!spi_read_dma(&r)) break;}
else r = 1;
}while(0);
SCRN_Command();
SCRN_RST_set(1);
return r;
}
// write data by SPI over DMA (but blocking!)
// !!!! don't do anything with `data` until transmission complete !!!!
int ili9341_writedata(uint8_t *data, uint32_t N){
return dmardwr(data, NULL, N);
}
// blocking read data by DMA
int ili9341_readdata(uint8_t *data, uint32_t N){
return dmardwr(data, data, N);
}
int ili9341_readregdma(uint8_t reg, uint8_t *data, uint32_t N){
SCRN_Command();
SCRN_RST_set(0);
int r = 0; int r = 0;
do{ do{
if(!spi_write(data, N)) break; if(!spi_write(&reg, 1)) break;
if(!spi_waitbsy()) break; if(!spi_waitbsy()) break;
SCRN_Data();
if(!dmardwr(data, data, N)) break;
r = 1; r = 1;
}while(0); }while(0);
SCRN_Command(); SCRN_Command();
@ -191,32 +230,14 @@ int ili9341_writedata(const uint8_t *data, uint32_t N){
static int fillcmd(uint16_t color, uint8_t cmd, int sz){ static int fillcmd(uint16_t color, uint8_t cmd, int sz){
uint16_t rc = __builtin_bswap16(color); uint16_t rc = __builtin_bswap16(color);
//USB_sendstr("rc="); USB_sendstr(u2str(rc)); newline(); if(!ili9341_writecmd(cmd)) return 0;
SCRN_Command(); for(int i = 0; i < COLORBUFSZ; ++i) colorbuf[i] = rc; // prepare buffer to write
SCRN_RST_set(0); while(sz){
int r = 0; int portion = (sz > COLORBUFSZ) ? COLORBUFSZ : sz;
if(!spi_write(&cmd, 1)) goto rtn; if(!ili9341_writedata((uint8_t*)colorbuf, portion * 2)) return 0; // multiply by 2: we are writing uint16_t!
if(!spi_waitbsy()) goto rtn; sz -= portion;
r = 1;
SCRN_Data();
uint16_t black = 0;
for(int i = 0; i < sz; ++i){
IWDG->KR = IWDG_REFRESH;
if(i%80 == 0){
if(!spi_write((uint8_t*)&black, 2)){
r = 0;
break;
}
} else if(!spi_write((uint8_t*)&rc, 2)){
r = 0;
break;
}
} }
if(!spi_waitbsy()) r = 0; return 1;
rtn:
SCRN_Command();
SCRN_RST_set(1);
return r;
} }
// fill start // fill start

View File

@ -163,7 +163,14 @@
#define SCRNSZMIN 240 #define SCRNSZMIN 240
#define SCRNSZ (SCRNSZMAX*SCRNSZMIN) #define SCRNSZ (SCRNSZMAX*SCRNSZMIN)
#define DEFMADCTL (ILI9341_MADCTL_MY | ILI9341_MADCTL_RGB) // Different orientations
// default orientation: w=320, h=240, zero in upper left corner, connector is from the left
#define DEFMADCTL (ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_RGB)
#define SCRNW SCRNSZMAX
#define SCRNH SCRNSZMIN
#define COLORBUFSZ (2*SCRNW)
extern uint16_t colorbuf[];
int ili9341_init(); int ili9341_init();
int ili9341_readreg(uint8_t reg, uint8_t *data, uint32_t N); int ili9341_readreg(uint8_t reg, uint8_t *data, uint32_t N);
@ -171,7 +178,10 @@ int ili9341_writereg(uint8_t reg, const uint8_t *data, uint32_t N);
int ili9341_writereg16(uint8_t reg, uint16_t data); int ili9341_writereg16(uint8_t reg, uint16_t data);
int ili9341_writereg32(uint8_t reg, uint16_t data1, uint16_t data2); int ili9341_writereg32(uint8_t reg, uint16_t data1, uint16_t data2);
int ili9341_writecmd(uint8_t cmd); int ili9341_writecmd(uint8_t cmd);
int ili9341_writedata(const uint8_t *data, uint32_t N); int ili9341_writedata(uint8_t *data, uint32_t N);
int ili9341_readdata(uint8_t *data, uint32_t N);
int ili9341_readregdma(uint8_t reg, uint8_t *data, uint32_t N);
int ili9341_fill(uint16_t color); int ili9341_fill(uint16_t color);
int ili9341_filln(uint16_t color); int ili9341_filln(uint16_t color);
int ili9341_fillp(uint16_t color, int sz); int ili9341_fillp(uint16_t color, int sz);

View File

@ -24,6 +24,7 @@
#include "hardware.h" #include "hardware.h"
#include "i2c.h" #include "i2c.h"
#include "proto.h" #include "proto.h"
#include "screen.h"
#include "strfunc.h" #include "strfunc.h"
#include "usb.h" #include "usb.h"
@ -35,6 +36,8 @@ void sys_tick_handler(void){
++Tms; ++Tms;
} }
// SPI setup done in `screen.h`
int main(void){ int main(void){
char inbuff[MAXSTRLEN+1]; char inbuff[MAXSTRLEN+1];
if(StartHSE()){ if(StartHSE()){
@ -112,6 +115,7 @@ int main(void){
const char *ans = cmd_parser(inbuff); const char *ans = cmd_parser(inbuff);
if(ans) USB_sendstr(ans); if(ans) USB_sendstr(ans);
} }
process_screen();
//process_keys(); //process_keys();
} }
} }

View File

@ -10,6 +10,10 @@ commonproto.c
commonproto.h commonproto.h
flash.c flash.c
flash.h flash.h
font14.h
fontNumb8.h
fonts.c
fonts.h
hardware.c hardware.c
hardware.h hardware.h
hashgen/hashgen.c hashgen/hashgen.c
@ -27,6 +31,8 @@ proto.c
proto.h proto.h
ringbuffer.c ringbuffer.c
ringbuffer.h ringbuffer.h
screen.c
screen.h
spi.c spi.c
spi.h spi.h
steppers.c steppers.c

Before

Width:  |  Height:  |  Size: 402 B

After

Width:  |  Height:  |  Size: 457 B

View File

@ -22,6 +22,7 @@
#include "i2c.h" #include "i2c.h"
#include "proto.h" #include "proto.h"
#include "ili9341.h" #include "ili9341.h"
#include "screen.h"
#include "strfunc.h" #include "strfunc.h"
#include "version.inc" #include "version.inc"
@ -62,7 +63,7 @@ static void sendkeyu(const char *cmd, int parno, uint32_t u){
// `sendkey` for uint32_t out in hex // `sendkey` for uint32_t out in hex
static void sendkeyuhex(const char *cmd, int parno, uint32_t u){ static void sendkeyuhex(const char *cmd, int parno, uint32_t u){
USB_sendstr(cmd); USB_sendstr(cmd);
if(parno > -1) USB_sendstr(u2str((uint32_t)parno)); if(parno > -1) USB_sendstr(uhex2str((uint32_t)parno));
USB_putbyte('='); USB_sendstr(uhex2str(u)); newline(); USB_putbyte('='); USB_sendstr(uhex2str(u)); newline();
} }
@ -237,6 +238,14 @@ static int scrnrdwr4(const char *cmd, int parno, const char *c, int32_t i){
sendkeyuhex(cmd, parno, i); sendkeyuhex(cmd, parno, i);
return RET_GOOD; return RET_GOOD;
} }
static int scrnrdn(const char *cmd, int parno, const char *c, int32_t i){
if(parno < 0 || parno > 255) return RET_WRONGPARNO;
if(!c || i < 1 || i > COLORBUFSZ*2) return RET_WRONGARG;
if(!ili9341_readregdma(parno, (uint8_t*)colorbuf, i)) return RET_BAD;
sendkey(cmd, parno, i);
hexdump(USB_sendstr, (uint8_t*)colorbuf, i);
return RET_GOOD;
}
static int scrncmd(const char _U_ *cmd, int parno, const char _U_ *c, int32_t _U_ i){ static int scrncmd(const char _U_ *cmd, int parno, const char _U_ *c, int32_t _U_ i){
if(parno < 0 || parno > 255) return RET_WRONGPARNO; if(parno < 0 || parno > 255) return RET_WRONGPARNO;
if(!ili9341_writecmd((uint8_t)parno)) return RET_BAD; if(!ili9341_writecmd((uint8_t)parno)) return RET_BAD;
@ -266,30 +275,30 @@ static int scrninit(const char _U_ *cmd, int _U_ parno, const char _U_ *c, int32
static int scrnfill(const char *cmd, int parno, const char *c, int32_t i){ static int scrnfill(const char *cmd, int parno, const char *c, int32_t i){
if(parno < 0) parno = RGB(0xf, 0x1f, 0xf); if(parno < 0) parno = RGB(0xf, 0x1f, 0xf);
if(parno > 0xffff) return RET_WRONGPARNO; if(parno > 0xffff) return RET_WRONGPARNO;
if(!c){if(!ili9341_fill((uint16_t)parno)) return RET_BAD; if(!c){if(!(i=ili9341_fill((uint16_t)parno))) return RET_BAD;
}else{ }else{
if(i < 1) return RET_WRONGARG; if(i < 1) return RET_WRONGARG;
if(!ili9341_fillp((uint16_t)parno, -i)) return RET_BAD; if(!ili9341_fillp((uint16_t)parno, -i)) return RET_BAD;
} }
sendkeyuhex(cmd, -1, i); sendkeyu(cmd, parno, i);
return RET_GOOD; return RET_GOOD;
} }
static int scrnfilln(const char *cmd, int _U_ parno, const char *c, int32_t i){ static int scrnfilln(const char *cmd, int parno, const char *c, int32_t i){
if(parno < 0) parno = RGB(0xf, 0x1f, 0xf); if(parno < 0) parno = RGB(0xf, 0x1f, 0xf);
if(parno > 0xffff) return RET_WRONGPARNO; if(parno > 0xffff) return RET_WRONGPARNO;
if(!c){if(!ili9341_filln((uint16_t)parno)) return RET_BAD; if(!c){if(!(i=ili9341_filln((uint16_t)parno))) return RET_BAD;
}else{ }else{
if(i < 1) return RET_WRONGARG; if(i < 1) return RET_WRONGARG;
if(!ili9341_fillp((uint16_t)parno, i)) return RET_BAD; if(!ili9341_fillp((uint16_t)parno, i)) return RET_BAD;
} }
sendkeyuhex(cmd, -1, i); sendkeyu(cmd, parno, i);
return RET_GOOD; return RET_GOOD;
} }
static int smadctl(const char *cmd, int _U_ parno, const char *c, int32_t i){ static int smadctl(const char *cmd, int parno, const char *c, int32_t i){
if(!c) i = 0; if(!c) i = 0;
if(i < 0 || i > 255) return RET_WRONGARG; if(i < 0 || i > 255) return RET_WRONGARG;
if(!ili9341_writereg(ILI9341_MADCTL, (uint8_t*)&i, 1)) return RET_BAD; if(!ili9341_writereg(ILI9341_MADCTL, (uint8_t*)&i, 1)) return RET_BAD;
sendkeyuhex(cmd, -1, i); sendkeyuhex(cmd, parno, i);
return RET_GOOD; return RET_GOOD;
} }
static int scolrow(int col, const char *cmd, int parno, const char *c, int32_t i){ static int scolrow(int col, const char *cmd, int parno, const char *c, int32_t i){
@ -306,6 +315,66 @@ static int scol(const char *cmd, int parno, const char *c, int32_t i){
static int srow(const char *cmd, int parno, const char *c, int32_t i){ static int srow(const char *cmd, int parno, const char *c, int32_t i){
return scolrow(0, cmd, parno, c, i); return scolrow(0, cmd, parno, c, i);
} }
static int sread(const char *cmd, int parno, const char _U_ *c, int32_t _U_ i){
if(parno < 0 || parno > COLORBUFSZ*2) return RET_WRONGARG;
if(!(parno = ili9341_readdata((uint8_t*)colorbuf, parno))) return RET_BAD;
USB_sendstr(cmd); USB_sendstr(u2str(parno)); newline();
hexdump(USB_sendstr, (uint8_t*)colorbuf, parno);
return RET_GOOD;
}
static int scls(const char *cmd, int parno, const char *c, int32_t i){
// fg=bg, default: fg=0xffff, bg=0
if(parno < 0 || parno > 0xffff) parno = 0xffff;
if(!c) i = 0;
setBGcolor(i);
setFGcolor(parno);
ClearScreen();
sendkeyuhex(cmd, parno, i);
return RET_GOOD;
}
static int scolor(const char *cmd, int parno, const char *c, int32_t i){
// fg=bg, default: fg=0xffff, bg=0
if(parno < 0 || parno > 0xffff) parno = 0xffff;
if(!c) i = 0;
setBGcolor(i);
setFGcolor(parno);
sendkeyuhex(cmd, parno, i);
return RET_GOOD;
}
static int sputstr(const char _U_ *cmd, int parno, const char *c, int32_t _U_ i){
if(!c) return RET_WRONGARG;
if(parno < 0) parno = 0;
if(parno > SCRNH-1) parno = SCRNH-1;
PutStringAt(0, parno, c);
UpdateScreen(parno - 14, parno+2);
USB_sendstr("put string: '"); USB_sendstr(c); USB_sendstr("'\n");
return RET_GOOD;
}
static int sstate(const char _U_ *cmd, int _U_ parno, const char _U_ *c, int32_t _U_ i){
const char *s = "unknown";
switch(getScreenState()){
case SCREEN_INIT:
s = "init";
break;
case SCREEN_W4INIT:
s = "wait for init";
break;
case SCREEN_RELAX:
s = "relax";
break;
case SCREEN_CONVBUF:
s = "convert buffer";
break;
case SCREEN_UPDATENXT:
s = "update next";
break;
case SCREEN_ACTIVE:
s = "transmission in progress";
break;
}
USB_sendstr("ScreenState="); USB_sendstr(s); newline();
return RET_GOOD;
}
typedef struct{ typedef struct{
int (*fn)(const char*, int, const char*, int32_t); int (*fn)(const char*, int, const char*, int32_t);
@ -334,15 +403,21 @@ commands cmdlist[] = {
{scrnrst, "Srst", "reset (1/0)"}, {scrnrst, "Srst", "reset (1/0)"},
{scrnrdwr, "Sreg", "read/write 8-bit register"}, {scrnrdwr, "Sreg", "read/write 8-bit register"},
{scrnrdwr4, "Sregx", "read/write 32-bit register"}, {scrnrdwr4, "Sregx", "read/write 32-bit register"},
{scrnrdn, "Sregn", "read from register x =n bytes"},
{scrncmd, "Scmd", "write 8bit command"}, {scrncmd, "Scmd", "write 8bit command"},
{scrndata, "Sdat", "write 8bit data"}, {scrndata, "Sdat", "write 8bit data"},
{scrndata4, "Sdatx", "write x bytes of data"}, {scrndata4, "Sdatn", "write x bytes of =data"},
{sread, "Sread", "read "},
{scrninit, "Sini", "init screen"}, {scrninit, "Sini", "init screen"},
{scrnfill, "Sfill", "fill screen with color (=npix)"}, {scrnfill, "Sfill", "fill screen with color (=npix)"},
{scrnfilln, "Sfilln", "fill screen (next) with color (=npix)"}, {scrnfilln, "Sfilln", "fill screen (next) with color (=npix)"},
{smadctl, "Smad", "change MADCTL"}, {smadctl, "Smad", "change MADCTL"},
{scol, "Scol", "set column limits (low=high)"}, {scol, "Scol", "set column limits (low=high)"},
{srow, "Srow", "set row limits (low=high)"}, {srow, "Srow", "set row limits (low=high)"},
{scls, "Scls", "clear screen fg=bg"},
{scolor, "Scolor", "seg color fg=bg"},
{sputstr, "Sstr", "put string y=string"},
{sstate, "Sstate", "current screen state"},
{NULL, "ADC commands", NULL}, {NULL, "ADC commands", NULL},
{adcval, "ADC", "get ADCx value (without x - for all)"}, {adcval, "ADC", "get ADCx value (without x - for all)"},
{adcvoltage, "ADCv", "get ADCx voltage (without x - for all)"}, {adcvoltage, "ADCv", "get ADCx voltage (without x - for all)"},

View File

@ -0,0 +1,304 @@
/*
* This file is part of the nitrogen project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h> // memset, memcpy
#include <stdio.h>
#include "fonts.h"
#include "hardware.h"
#include "screen.h"
#include "spi.h" // spi_status
#include "ili9341.h"
#include "usb.h"
#ifdef EBUG
#include "strfunc.h"
#endif
#define SWAPINT(a,b) do{register int r = a; a = b; b = r;}while(0)
// sprites 8x8 bytes with 8bit foreground and 8bit background
// X coordinate - from left to right!
// Y coordinate - from top to bottom!
// (0,0) is top left corner
// full screen buffer size in bytes/words (depending on sprite size)
// !!! If sprite width != 8, change all code !!!
#define SCREENBUF_SZ (SCRNSZ/SPRITEWD)
// amount of sprites by both axes
#define SCRNSPRITEW (SCRNW/SPRITEWD)
#define SCRNSPRITEH (SCRNH/SPRITEHT)
#define SPRITE_SZ (SCRNSPRITEW * SCRNSPRITEH)
// pixel buffer
static uint8_t screenbuf[SCREENBUF_SZ];
// color buffers
static uint16_t foreground[SPRITE_SZ];
static uint16_t background[SPRITE_SZ];
// borders of string numbers to update screen (including!)
static int uy0, uy1;
// index of pixel in given updating block
static int updidx = 0; // ==-1 to initialize update
// next data portion size (in bytes!), total amount of bytes in update buffer
static int portionsz = 0, updbuffsz;
static uint16_t fgColor = 0xff, bgColor = 0; // foreground and background colors
void setBGcolor(uint16_t c){bgColor = c;}
void setFGcolor(uint16_t c){fgColor = c;}
static screen_state ScrnState = SCREEN_INIT;
screen_state getScreenState(){return ScrnState;}
/**
* @brief UpdateScreen - request to screen updating from lines y0 to y1 (including)
* @param y0, y1 - first and last line of field to update
*/
void UpdateScreen(int y0, int y1){
if(y0 > y1) SWAPINT(y0, y1);
if(y0 < 0) y0 = 0;
if(y1 > SCRNH) y1 = SCRNH - 1;
//USB_sendstr("y0="); USB_sendstr(i2str(y0)); newline();
//USB_sendstr("y1="); USB_sendstr(i2str(y1)); newline();
uy0 = y0; uy1 = y1;
updidx = -1;
updbuffsz = SCRNW * (1 + y1 - y0);
}
/**
* @brief FillScreen - fill screen buffer with current bgColor
*/
void ClearScreen(){
memset(screenbuf, 0, SCREENBUF_SZ);
int i;
for(i = 0; i < SPRITE_SZ; ++i){
foreground[i] = fgColor;
background[i] = bgColor;
}
USB_sendstr("total spsz="); USB_sendstr(i2str(i)); newline();
foreground[SPRITE_SZ-5] = 0x1234;
foreground[SPRITE_SZ-21] = 0x4321;
UpdateScreen(0, SCRNH-1);
}
/**
* @brief DrawPix - set or clear pixel
* @param X, Y - pixel coordinates (could be outside of screen)
* @param pix - 1 - foreground, 0 - background
*/
void DrawPix(int X, int Y, uint8_t pix){
if(X < 0 || X > SCRNW-1 || Y < 0 || Y > SCRNH-1) return; // outside of screen
// now calculate coordinate of pixel
int16_t spritex = X/SPRITEWD, spriteidx = spritex + SCRNSPRITEW * Y / SPRITEHT;
uint8_t *ptr = &screenbuf[Y*SCRNSPRITEW + spritex]; // pointer to byte with 8 pixels
if(pix) *ptr |= 1 << (7 - (X%8));
else *ptr &= ~(1 << (7 - (X%8)));
foreground[spriteidx] = fgColor;
background[spriteidx] = bgColor;
}
/**
* @brief invertSpriteColor - change bg-fg colors in given rectangle
* @param xmin, xmax, ymin, ymax - rectangle coordinates
*/
void invertSpriteColor(int xmin, int xmax, int ymin, int ymax){
if(xmin < 0) xmin = 0;
if(xmax > SCRNW-1) xmax = SCRNW-1;
if(ymin < 0) ymin = 0;
if(ymax > SCRNH-1) ymax = SCRNH-1;
if(xmin > xmax) SWAPINT(xmin, xmax);
if(ymin > ymax) SWAPINT(ymin, ymax);
// convert to sprite coordinates
xmin /= SPRITEWD; xmax = (xmax + SPRITEWD - 1) / SPRITEWD;
ymin /= SPRITEHT; ymax = (ymax + SPRITEHT - 1) / SPRITEHT;
for(int y = ymin; y <= ymax; ++y){
int idx = y * SCRNSPRITEW + xmin;
uint16_t *f = foreground + idx, *b = background + idx;
for(int x = xmin; x <= xmax; ++x, ++f, ++b){
register uint16_t r = *f;
*f = *b; *b = r;
}
}
}
// TODO in case of low speed: draw at once full line?
/**
* @brief DrawCharAt - draws character @ position X,Y (this point is left baseline corner of char!)
* character will be drawn with current fg and bg colors
* @param X, Y - started point
* @param Char - char to draw
* @return char width
*/
uint8_t DrawCharAt(int X, int Y, uint8_t Char){
const uint8_t *curchar = font_char(Char);
if(!curchar) return 0;
// now change Y coordinate to left upper corner of font
Y += curfont->baseline - curfont->height + 1;
// height and width of letter in pixels
uint8_t h = curfont->height, w = *curchar++; // now curchar is pointer to bits array
uint8_t lw = curfont->bytes / h; // width of letter in bytes
for(uint8_t row = 0; row < h; ++row){
int Y1 = Y + row;
for(uint8_t col = 0; col < w; ++col){
register uint8_t pix = curchar[row*lw + (col/8)] & (1 << (7 - (col%8)));
DrawPix(X + col, Y1, pix);
}
}
return w;
}
/**
* @brief PutStringAt - draw text string @ screen
* @param X, Y - base coordinates
* @param str - string to draw
* @return - X-coordinate of last pixel
*/
int PutStringAt(int X, int Y, const char *str){
if(!str) return 0;
while(*str){
X += DrawCharAt(X, Y, (uint8_t)*str++);
}
return X;
}
/**
* @brief CenterStringAt - draw string @ center line
* @param Y - y coordinate
* @param str - string
* @return - text width in pixels
*/
int CenterStringAt(int Y, const char *str){
int l = strpixlen(str);
return PutStringAt((SCRNW - l)/2, Y, str);
}
// full string length in pixels
int strpixlen(const char *str){
int l = 0;
while(*str){
const uint8_t *c = font_char(*str++);
if(c) l += *c;
}
return l;
}
// convert buffer to update (return 0 if all sent)
static int convbuf(){
// DBG("convert buffer");
int rest = updbuffsz - updidx;
/* USB_sendstr("updbuffsz="); USB_sendstr(i2str(updbuffsz));
USB_sendstr("\nupdidx="); USB_sendstr(i2str(updidx));
USB_sendstr("\nrest="); USB_sendstr(i2str(rest)); newline();*/
if(rest < 1) return 0;
if(rest > COLORBUFSZ) rest = COLORBUFSZ;
portionsz = rest;
// USB_sendstr("portionsz="); USB_sendstr(i2str(portionsz)); newline();
int Y = uy0 + updidx / SCRNW; // starting Y of updating string
uint16_t *o = colorbuf; // output color data
uint8_t *i = screenbuf + (Y*SCRNSPRITEW); // starting portion of pixel info
while(rest > 0){
int spidx = (Y/SPRITEHT)*SCRNSPRITEW; // index in color array
uint16_t *fg = foreground + spidx, *bg = background + spidx;
for(int X = 0; X < SCRNSPRITEW; ++X, ++fg, ++bg, ++i){
// prepare colors for SPI transfer
uint16_t f = __builtin_bswap16(*fg++), b = __builtin_bswap16(*bg++);
uint8_t pix = *i;
if(Y==239){
USB_sendstr("X="); USB_sendstr(i2str(X)); newline();
USB_sendstr("f="); USB_sendstr(uhex2str(f)); newline();}
for(int idx = 0; idx < SPRITEWD; ++idx){ // now check bits in pixels mask
*o++ = (pix & 0x80) ? f : b;
pix <<= 1;
++updidx; --rest;
}
}
++Y;
}
return 1;
}
// check SPI timeout
static uint32_t Tscr_last = 0;
static int chk_tmout(){
if(Tms - Tscr_last > SCRN_SPI_TIMEOUT){
ScrnState = SCREEN_INIT;
UpdateScreen(0, SCRNH-1);
return 1;
}
return 0;
}
/**
* @brief process_screen - screen state machine processing
*/
void process_screen(){
switch(ScrnState){
case SCREEN_INIT: // try to init SPI and screen
DBG("SCREEN_INIT");
spi_setup();
if(ili9341_init()) ScrnState = SCREEN_RELAX;
else{
Tscr_last = Tms;
ScrnState = SCREEN_W4INIT;
}
break;
case SCREEN_W4INIT:
if(Tms - Tscr_last > SCRN_W4INI_TIMEOUT) ScrnState = SCREEN_INIT;
break;
case SCREEN_RELAX: // check need of updating
if(updidx > -1) return;
DBG("Need to update");
if(!ili9341_setcol(0, SCRNW-1)) return;
if(!ili9341_setrow(uy0, uy1)) return;
if(!ili9341_writecmd(ILI9341_RAMWR)) return;
updidx = 0;
Tscr_last = Tms;
ScrnState = SCREEN_ACTIVE; // now we are ready to update screen
// fallthrough
case SCREEN_ACTIVE: // SPI transmission active
if(chk_tmout()){
DBG("timeout");
return;
}
if(spi_status != SPI_READY){
DBG("SPI not ready");
return;
}
// convert & update next field
ScrnState = SCREEN_CONVBUF;
// fallthrough
case SCREEN_CONVBUF: // convert buffer for sending
if(!convbuf()){
ScrnState = SCREEN_RELAX;
return;
}
Tscr_last = Tms; // for DMA writing timeout
ScrnState = SCREEN_UPDATENXT;
// fallthrough
case SCREEN_UPDATENXT: // send next data portion
if(chk_tmout()){
DBG("timeout");
return;
}
// portionsz in pixels (uint16_t), sending size in bytes!
if(!ili9341_writedata((uint8_t*)colorbuf, portionsz * 2)) return;
Tscr_last = Tms; // wait DMA writing timeout
ScrnState = SCREEN_ACTIVE;
break;
default:
break;
}
}

View File

@ -0,0 +1,55 @@
/*
* This file is part of the nitrogen project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
typedef enum{ // screen states
SCREEN_INIT // init stage
,SCREEN_W4INIT // wait after last unsuccessfull update
,SCREEN_RELAX // nothing to do (screen is off)
,SCREEN_CONVBUF // convert next buffer portion
,SCREEN_UPDATENXT // update next block
,SCREEN_ACTIVE // transmission active - wait for SPI transfer ends
} screen_state;
// timeout (ms) in case of SPI error - 100ms
#define SCRN_SPI_TIMEOUT (100)
// wait if failed on init
#define SCRN_W4INI_TIMEOUT (1000)
// sprite width and height in pixels
#define SPRITEWD (8)
#define SPRITEHT (8)
screen_state getScreenState();
void ClearScreen();
void UpdateScreen(int y0, int y1);
void setBGcolor(uint16_t c);
void setFGcolor(uint16_t c);
void invertSpriteColor(int xmin, int xmax, int ymin, int ymax);
void DrawPix(int X, int Y, uint8_t pix);
uint8_t DrawCharAt(int X, int Y, uint8_t Char);
int PutStringAt(int X, int Y, const char *str);
int CenterStringAt(int Y, const char *str);
int strpixlen(const char *str);
uint8_t *getScreenBuf();
void process_screen();

View File

@ -30,18 +30,35 @@ spiStatus spi_status = SPI_NOTREADY;
volatile uint32_t wctr; volatile uint32_t wctr;
#define WAITX(x) do{wctr = 0; while((x) && (++wctr < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0) #define WAITX(x) do{wctr = 0; while((x) && (++wctr < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0)
// SPI DMA Rx buffer (set by spi_write_dma call)
static uint8_t *rxbufptr = NULL;
static uint32_t rxbuflen = 0;
// init SPI2 to work with and without DMA // init SPI2 to work with and without DMA
// ILI9341: SCL 0->1; CS=0; command - DC=0, data - DC=1; 1 dummy clock pulse before 24/32 bit data read // ILI9341: SCL 0->1; CS=0; command - DC=0, data - DC=1; 1 dummy clock pulse before 24/32 bit data read
// Channel 4 - SPI2 Rx // Channel 4 - SPI2 Rx
// Channel 5 - SPI2 Tx // Channel 5 - SPI2 Tx
void spi_setup(){ void spi_setup(){
SPI2->CR1 = 0; // clear EN
//RCC->APB1RSTR = RCC_APB1RSTR_SPI2RST; // reset SPI
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// Baudrate = 0b011 - fpclk/16 = 2MHz; software slave management (without hardware NSS pin) // Baudrate = 0b011 - fpclk/16 = 2MHz; software slave management (without hardware NSS pin)
SPI2->CR1 = /*SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE |*/ SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI; SPI2->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI;
// 8bit; RXNE generates after 8bit of data in FIFO // 8bit; RXNE generates after 8bit of data in FIFO
SPI2->CR2 = SPI_CR2_FRXTH | SPI_CR2_DS_2|SPI_CR2_DS_1|SPI_CR2_DS_0 /*| SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN*/; SPI2->CR2 = SPI_CR2_FRXTH | SPI_CR2_DS_2|SPI_CR2_DS_1|SPI_CR2_DS_0 | SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
// setup SPI2 DMA
// Tx
DMA1_Channel5->CPAR = (uint32_t)&(SPI2->DR); // hardware
DMA1_Channel5->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TEIE; // memory increment, mem->hw, error interrupt
// Rx
DMA1_Channel4->CPAR = (uint32_t)&(SPI2->DR);
DMA1_Channel4->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE; // mem inc, hw->mem, Rx complete and error interrupt
NVIC_EnableIRQ(DMA1_Channel4_IRQn); // enable Rx interrupt
NVIC_EnableIRQ(DMA1_Channel5_IRQn); // enable Tx interrupt
spi_status = SPI_READY; spi_status = SPI_READY;
SPI2->CR1 |= SPI_CR1_SPE; SPI2->CR1 |= SPI_CR1_SPE;
DBG("SPI works");
} }
int spi_waitbsy(){ int spi_waitbsy(){
@ -63,21 +80,41 @@ int spi_write(const uint8_t *data, uint32_t n){
for(uint32_t x = 0; x < n; ++x){ for(uint32_t x = 0; x < n; ++x){
WAITX(!(SPI2->SR & SPI_SR_TXE)); WAITX(!(SPI2->SR & SPI_SR_TXE));
SPIDR = data[x]; SPIDR = data[x];
//WAITX(!(SPI2->SR & SPI_SR_RXNE));
//data[x] = SPI2->DR; // clear RXNE after last things
} }
return 1; return 1;
} }
/** /**
* @brief spi_send_dma - send data over SPI2 through DMA * @brief spi_send_dma - send data over SPI2 through DMA (used both for writing and reading)
* @param data - data to read * @param data - data to read
* @param rxbuf - pointer to receiving buffer (at least n bytes), can be also `data` (if `data` isn't const)
* @param n - length of data * @param n - length of data
* @return 0 if failed * @return 0 if failed
* !!! `data` buffer can be changed only after SPI_READY flag!
*/ */
int spi_write_dma(const uint8_t _U_ *data, uint32_t _U_ n){ int spi_write_dma(const uint8_t *data, uint8_t *rxbuf, uint32_t n){
if(spi_status != SPI_READY) return 0; if(spi_status != SPI_READY) return 0;
return 0; rxbufptr = rxbuf;
rxbuflen = n;
if(!spi_waitbsy()) return 0;
// clear SPI Rx FIFO
(void) SPI2->DR;
while(SPI2->SR & SPI_SR_RXNE) (void) SPI2->DR;
//DMA1_Channel4->CCR &= ~DMA_CCR_EN; // turn off to reconfigure
//DMA1_Channel5->CCR &= ~DMA_CCR_EN;
DMA1_Channel5->CMAR = (uint32_t) data;
DMA1_Channel5->CNDTR = n;
// check if user want to receive data
if(rxbuf){
DMA1_Channel4->CCR |= DMA_CCR_TCIE;
DMA1_Channel5->CCR &= ~DMA_CCR_TCIE; // turn off Tx ready interrupt
DMA1_Channel4->CMAR = (uint32_t) rxbuf;
DMA1_Channel4->CNDTR = n;
DMA1_Channel4->CCR |= DMA_CCR_EN; // turn on reception
}else DMA1_Channel5->CCR |= DMA_CCR_TCIE; // interrupt by Tx ready - user don't want reception
spi_status = SPI_BUSY;
DMA1_Channel5->CCR |= DMA_CCR_EN; // turn on transmission
return 1;
} }
/** /**
@ -86,31 +123,52 @@ int spi_write_dma(const uint8_t _U_ *data, uint32_t _U_ n){
* @param n - length of data * @param n - length of data
* @return n * @return n
*/ */
int spi_read(uint8_t _U_ *data, uint32_t _U_ n){ int spi_read(uint8_t *data, uint32_t n){
if(spi_status != SPI_READY){ if(spi_status != SPI_READY){
DBG("not ready"); DBG("not ready");
return 0; return 0;
} }
//SPI2->CR1 &= ~SPI_CR1_BIDIOE; // Rx if(!spi_waitbsy()) return 0;
// clear SPI Rx FIFO
(void) SPI2->DR;
while(SPI2->SR & SPI_SR_RXNE) (void) SPI2->DR; while(SPI2->SR & SPI_SR_RXNE) (void) SPI2->DR;
for(uint32_t x = 0; x < n; ++x){ for(uint32_t x = 0; x < n; ++x){
WAITX(!(SPI2->SR & SPI_SR_TXE)); WAITX(!(SPI2->SR & SPI_SR_TXE));
SPIDR = 0; SPIDR = 0;
WAITX(!(SPI2->SR & SPI_SR_RXNE)); WAITX(!(SPI2->SR & SPI_SR_RXNE));
data[x] = SPI2->DR; data[x] = SPIDR;
USB_sendstr("rd got "); USB_sendstr(uhex2str(data[x]));
newline();
} }
//SPI2->CR1 |= SPI_CR1_BIDIOE; // turn off clocking
return 1; return 1;
} }
/** /**
* @brief spi_read_dma - read SPI2 data through DMA * @brief spi_read_dma - got buffer read by DMA
* @param data - data to read * @param n (o) - length of rxbuffer
* @param n - length of data * @return amount of bytes read
* @return n
*/ */
int spi_read_dma(uint8_t _U_ *data, uint32_t _U_ n){ uint8_t *spi_read_dma(uint32_t *n){
if(spi_status != SPI_READY) return 0; if(spi_status != SPI_READY || rxbuflen == 0) return NULL;
return 0; if(n) *n = rxbuflen - DMA1_Channel4->CNDTR; // in case of error buffer would be underfull
rxbuflen = 0; // prevent consequent readings
return rxbufptr;
} }
// Rx ready interrupt
void dma1_channel4_isr(){
spi_status = SPI_READY; // ready independent on errors or Rx ready
DMA1->IFCR = DMA_IFCR_CTCIF4 | DMA_IFCR_CTEIF4;
// turn off DMA
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
DMA1_Channel5->CCR &= ~DMA_CCR_EN;
}
// Tx ready interrupt
void dma1_channel5_isr(){
spi_status = SPI_READY; // ready independent on errors or Tx ready
DMA1->IFCR = DMA_IFCR_CTCIF5 | DMA_IFCR_CTEIF5;
// turn off DMA
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
DMA1_Channel5->CCR &= ~DMA_CCR_EN;
}

View File

@ -30,6 +30,6 @@ extern spiStatus spi_status;
void spi_setup(); void spi_setup();
int spi_waitbsy(); int spi_waitbsy();
int spi_write(const uint8_t *data, uint32_t n); int spi_write(const uint8_t *data, uint32_t n);
int spi_write_dma(const uint8_t *data, uint32_t n); int spi_write_dma(const uint8_t *data, uint8_t *rxbuf, uint32_t n);
int spi_read(uint8_t *data, uint32_t n); int spi_read(uint8_t *data, uint32_t n);
int spi_read_dma(uint8_t *data, uint32_t n); uint8_t *spi_read_dma(uint32_t *n);

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "152" #define BUILD_NUMBER "217"
#define BUILD_DATE "2023-05-09" #define BUILD_DATE "2023-05-11"