Full Code of ArjanteMarvelde/uSDR-pico for AI

main 1253502fac2c cached
33 files
623.1 KB
373.0k tokens
66 symbols
1 requests
Download .txt
Showing preview only (643K chars total). Download the full file or copy to clipboard to get everything.
Repository: ArjanteMarvelde/uSDR-pico
Branch: main
Commit: 1253502fac2c
Files: 33
Total size: 623.1 KB

Directory structure:
gitextract_jg7cwinb/

├── .github/
│   └── workflows/
│       └── cmake.yml
├── CMakeLists.txt
├── README.md
├── dsp.c
├── dsp.h
├── dsp_fft.c
├── dsp_tim.c
├── fix_fft.c
├── fix_fft.h
├── font16.c
├── font20.c
├── font24.c
├── font7spp.c
├── font8.c
├── fontAR.c
├── fontGR.c
├── fontSYM16.c
├── fontSYM32.c
├── fonts.h
├── fontub.c
├── fontubb.c
├── hmi.c
├── hmi.h
├── lcd.c
├── lcd.h
├── monitor.c
├── monitor.h
├── relay.c
├── relay.h
├── si5351.c
├── si5351.h
├── uSDR.c
└── uSDR.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/cmake.yml
================================================
name: CMake

on:
  # Trigger the workflow on push or pull request,
  # but only for the main branch
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

env:
  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
  BUILD_TYPE: Release
  PICO_SDK_FETCH_FROM_GIT: 1

jobs:
  build-firmware:
    # The CMake configure and build commands are platform agnostic and should work equally
    # well on Windows or Mac.  You can convert this to a matrix build if you need
    # cross-platform coverage.
    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
    runs-on: ubuntu-latest
    name: build-frmware

    steps:
    - uses: actions/checkout@v2

    - name: Install libs
      # Some projects don't allow in-source building, so create a separate build directory
      # We'll use this as our working directory for all subsequent commands
      run: sudo apt-get install -y gcc-arm-none-eabi

    - name: Create Build Environment
      shell: bash
      run: cmake -E make_directory ${{runner.workspace}}/build

    - name: Configure CMake
      shell: bash
      working-directory: ${{runner.workspace}}/build
      run: cmake $GITHUB_WORKSPACE

    - name: Build firmware
      working-directory: ${{runner.workspace}}/build
      shell: bash
      run: cmake --build .



================================================
FILE: CMakeLists.txt
================================================
# Generated Cmake Pico project file
#
# After changing this file, empty the build folder and execute from there:  
#     cmake -G "Ninja" ..
#

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# initalize pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)

project(uSDR-Pico C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1
# uSDR.c	main loop and initialisation of the software
# lcd.c		LCD driver stuff; pay attention, X different HW implementations exist
# si5351.c	The drivers for setting output frequency and phase in the SI5351 chip
# dsp.c		The signal processing stuff, either timedomain or frequency domain
# fix_fft.c	The FFT transformations in fixed point format
# hmi.c		All user interaction, controlling freq, modulation, levels, etc
# monitor.c	A tty shell on a serial interface
# relay.c	Switching for the band filter and attenuator relays
# font?.c	Graphical character fonts
add_executable(uSDR-Pico 
	uSDR.c 
	lcd.c 
	si5351.c 
	dsp.c 
	fix_fft.c 
	hmi.c 
	monitor.c 
	relay.c
	font7spp.c
	font8.c
	font16.c
	font20.c
	font24.c
	fontub.c
	fontubb.c
	fontAR.c
	fontGR.c
	fontSYM32.c
	fontSYM16.c
)

target_compile_options(uSDR-Pico PRIVATE -Wall)
pico_set_program_name(uSDR-Pico "uSDR-Pico")
pico_set_program_version(uSDR-Pico "4.0")

# Pull in our pico_stdlib which aggregates commonly used features
target_link_libraries(uSDR-Pico pico_stdlib)

# Disable uart output, enable usb output
pico_enable_stdio_uart(uSDR-Pico 0)
pico_enable_stdio_usb(uSDR-Pico 1)

# Add any user requested libraries
target_link_libraries(uSDR-Pico
        pico_stdlib
		pico_multicore
		hardware_i2c
		hardware_spi
		hardware_pwm
        hardware_gpio
        hardware_timer
        hardware_clocks
		hardware_pll
		hardware_adc
		hardware_dma
        )
		
# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(uSDR-Pico)



================================================
FILE: README.md
================================================
![uSDR-Pico 4](https://github.com/ArjanteMarvelde/uSDR-pico/blob/main/doc/uSDR-Pico-4.jpg)  

The new V4.0 is now available:  
- Integrated audio on the CPU board  
- Moved VFO to Mixer board    
- Use discrete MMIC for LNA on RX board  
- New low power TX board  
- New layout BPF board  
- Proper bus connectors for all 5 boards,  
- Increased board size: 2" x 3.7", with the bus connectors this enables a cleaner stack  
- LCD graphical display (ILI9341 based: 320x240)  
- No more RS232, replaced with USB interface which can also be used for programming  
- Recalculated all filters  

The V4.0 schematics are now available in KiCAD format, so open for all to adapt. In the package I included a library with some dedicated definitions. Note that there are some patches needed to make things functional. These are described in the documentation. New software to run on this upgrade is also available as a package. Please update your SDK before building.

The V4.1 SW package is also available. This version only works when the patches on the HW have been made, as described in the [V4.10](https://github.com/ArjanteMarvelde/uSDR-pico/blob/main/doc/uSDR%20-%20v4.10.pdf) documentation. 

Still to be done:   
- More software updates   

# uSDR-pico
This Git repository contains a Micro-SDR implementation, based on a RP2040 Pi Pico.  

The project is highly experimental, foremost intended to investigate how the Pico HW and SDK work with an application like this. Also, it is a platform to experiment with digital signal processing techniques. The repository contains the code for an experimental implementation of the control and signal processing for a Quadrature Sampling Detector (QSD) and - Exciter (QSE) based transceiver. 
For completeness, the repository contains the electronic design of some modules that cover the mixing, filtering and RF amplification, as I have implemented in my prototype. See the *doc* subdirectory for full documentation.   

The ZIP files contain a consistent package, but the latest code with all the bug fixes and some new features is contained in the files in the main directory.  
Starting with the V3.00 package **uSDR-pico** contains *two signal processing engines*, selectable with a compile switch in uSDR.h. The first engine is the  time domain processor, more or less as in V2.00, and the second engine is a new FFT-based frequency domain processor.  
For a more detailed description of the software and the hardware, again refer to the elaborate documentation.  

The processor platform is a Pi Pico module, with an RP2040 device. This processor has dual cores running at 125MHz each, and a very configurable I/O which eases the HW design enormously. The platform can be overclocked, but some functions seem to become unstable when pushed too far. It is one of the topics for further investigation, although performance-wise not neccessary at the moment.
The software is distributed over the two cores: *core0* takes care of all user I/O and control functions, while *core1* performs all of the signal processing. The *core1* functionality consists of a TX-branch and an RX-branch, each invoked by a function that is synchronized by a timer every 64usec. Hence the signal processing rythm on *core1* effectively is 15.625kHz.  
On *core1* the three ADC channels are continuously sampled at maximum speed in round-robin mode. Samples are therefore taken every 6usec for each channel, maximum jitter between I and Q channels is 2usec, which has a negligible effect in the audio domain.  
For the time domain processing the TX and RX functions are executed within every 64usec timeslot, but for the frequency domain processing the samples are collected until half an FFT buffer is filled (512 samples), and hence this happens every 32msec (in background).  
On *core0* the main loop takes care of user I/O, all other controls and the monitor port. There is also a LED flashing timer callback functioning as a heartbeat.

The Pico controls an Si5351A clock module to obtain the switching clock for the QSE and QSD. The module outputs two synchronous square wave clocks on ch 0 and 1, whith selectable phase difference (0, 90, 180 or 270 degrees). The clock on ch2 is free to be used for other goals. The module is controlled over one of the I2C channels.
The display is a standard 16x2 LCD, but with an I2C interface. The display is connected through the other I2C channel, as well as the bus expanders for controlling the various relays.

## Open issues: 
- [ ] all SW to be tested on new v4.10 HW
- [ ] add simple waterfall over the 7.8kHz FFT band, as tuning assist  
- [ ] upgrade SDK and HW to the Pico 2 board
- [ ] audio interface over USB  
 

## Installing and using the SDK: 
Forget about collecting all the tooling manually in Windows, and avoid going through the hassle of keeping all things in sync. Instead, use Ubuntu on WSL (Windows Subsystem for Linux) and use the command line interface to generate your build. You can still edit the source files in Windows e.g. with Notepad++.  
### Ubuntu on WSL 
Make sure that virtualization is enabled in BIOS  
open Powershell as administrator  
- wsl --install

restart computer  
open Powershell as administrator  
- wsl.exe --list --online  
(to see the list of distro's)  
- wsl.exe --install [Distro]  
(I have used *Ubuntu-24.04*)

exit Powershell  
run ubuntu from the Start menu  
- sudo apt update  
- sudo apt upgrade  
- sudo apt install cmake gcc-arm-none-eabi build-essential libnewlib-arm-none-eabi git  
### Get SDK and other stuff 
run ubuntu from the Start menu  
- cd ~  
- mkdir pico  
- cd pico  
- git clone -b master https://github.com/raspberrypi/pico-sdk.git  
- cd pico-sdk  
- git submodule update --init   
- cd ~/pico  
- git clone -b master https://github.com/raspberrypi/pico-examples.git  
- cd ~  
- nano .bashrc  
add to the end: *export PICO_SDK_PATH=~/pico/pico-sdk*  
(now the *CMakeLists.txt* file no longer needs to set this)  
- save file and exit nano  
- exit  
### Test with blink example  
run ubuntu from the Start menu  
- cd ~/pico/pico-examples  
- mkdir build  
- cd build  
- cmake ..  
- cd blink  
- make
  
### Some hints  
In Ubuntu the windows C:\ is available under **/mnt/c**  
Likewise, the Documents folder: **/mnt/c/Users/<user>/Documents**  
Use "explorer.exe ." to open a windows explorer in the current directory  
  
## Building uSDR-pico:    
In ubuntu, git clone the uSDR-pico files: "cd ~~/pico; git clone https://github.com/ArjanteMarvelde/uSDR-pico".  
Create the build folder: "mkdir ~~/pico/uSDR-pico/build".  
Edit **~/pico/uSDR-pico/CMakeLists.txt** to have the correct environment parameter *PICO_SDK_PATH*, but it should also take it from the environment setting. In line with above installation this will be "~/pico/pico-sdk".  
Now create the build environment, "cd ~/pico/uSDR-pico/build; cmake ..".  
*Note* that every time you change something in **CMakeLists.txt** (like adding another source file to the build) you will have to clean the build folder and execute cmake once more: "cd ~/pico/uSDR-pico/build; rm -rf *; cmake ..".   

Now you have initialized the build environment and by executing **make** in the **build** folder, all SDK libraries and finally the Pi Pico loadable file **uSDR.uf2** will be created.  
*Note that when environment errors are encountered, it may help to empty the build folder and re-issue the cmake command.*   
Rebooting the Pico while the bootsel button is pressed will open a Windows Explorer window with the Pico shown as a Mass Storage Device (e.g. drive E:). Moving **uSDR.uf2** from the build to the Pico drive is as easy as dragging and dropping this file in windows explorer.  
  
## Releases  
Stable packages are archived in zip files. The source files in the root folder are newest and could be used to replace files from the zip archive. There are pre-built UF2 files for three display types, which could be tried. However, there are too many differnt types and addresses, so it is better to build a fresh one for your own implementation.   
The PCB files have been made with Eagle 5.11, and can be modified or otherwise re-used when needed. The CAM files for each board are packaged in separate zips, these can be used as-is to order PCBs.  

# Background
The Raspberry website contains the manuals, of which the *C-SDK description*, the *RP2040 datasheet* and the *Pico Pinout* are absolute must-reads when you start writing software.    
For calculating filters I have used the free software from [Iowa Hills](http://www.iowahills.com/8DownloadPage.html) (website has been down for a while, but files can be found using [Wayback Machine]( https://web.archive.org/web/20210819042054/http://www.iowahills.com/8DownloadPage.html))  
I also used the online FIR filter calculator [T-Filter](http://t-filter.engineerjs.com/) 

# Copyright notice
**The code and electronic designs as well as the implementations presented in this repository can be copied and modified freely, for non-commercial use.
Use for commercial purposes is allowed as well, as long as a reference to this repository is included in the product.**

See also my [Wave Form Generator](https://github.com/ArjanteMarvelde/uWFG-Pico) project. 


================================================
FILE: dsp.c
================================================
/*
 * dsp.c
 *
 * Created: Mar 2021
 * Author: Arjan te Marvelde
 * 
 * Signal processing of RX and TX branch, to be run on the second processor core (CORE1).
 * 
 * The actual DSP engine can be either FFT based in the frequency domain, or in the time domain.
 * In dsp.h this can be selected compile-time, by defining the environment variable DSP_FFT.
 *
 */

#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/platform.h"
#include "pico/time.h"
#include "pico/sem.h"
#include "hardware/structs/bus_ctrl.h"
#include "hardware/pwm.h"
#include "hardware/adc.h"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/timer.h"
#include "hardware/clocks.h"

#include "uSDR.h"
#include "dsp.h"
#include "hmi.h"
#include "fix_fft.h"


volatile bool    tx_enabled;												// TX branch active
volatile int32_t dsp_overrun;												// Overrun counter (could be underrun too)


/* 
 * DAC_RANGE defines PWM cycle, determining DAC resolution and PWM frequency.
 * DAC resolution = Vcc / DAC_RANGE
 * PWM frequency = Fsys / DAC_RANGE
 * A value of 250 means 125MHz/250=500kHz
 * ADC is 12 bit, so resolution is by definition 4096
 */
#define DAC_RANGE	256
#define DAC_BIAS	(DAC_RANGE/2)
#define ADC_RANGE	4096
#define ADC_BIAS	(ADC_RANGE/2)


volatile uint16_t dac_iq, dac_audio;


/*** External Interfaces, mostly used by hmi.c ***/

/*
 * MODE is modulation/demodulation 
 * This setting steers the signal processing branch chosen
 */
volatile int dsp_mode;
void dsp_setmode(int mode)
{
	dsp_mode = mode;
}


/*
 * S-Meter is for now based on RSSI, which is in fact the signal level in the preprocessor, 
 * in uV equivalent. The S level makes 6dB steps, i.e. factor 2 in voltage. The length of 
 * the (I,Q) vector (amplitude) of Rx signal is taken as reference for RSSI. This covers the 
 * whole sampled RX band, and is not specific to a particular station. To realize that, the 
 * S value must be calculated after FFT and for the specific tuning frequency.
 * Returned S value is highest bit set, i.e. RSSI of 512 corresponds with S9 (S=log2(RSSI))
 * This value was calibrated roughly by using the sam antenna and 
 *   comparing an IC R71-E with my uSDR HW implementation and ADC_INT=8.
 * +20dB means 10x the S-9 RSSI level, or >5120
 * +40dB means 100x the S-9 RSSI level, or >51200
 */
#define S940	51200
#define S930	16180
#define S920	5120
#define S910	1618
#define S9		512
#define S8		256
#define S7		128
#define S6		64
#define S5		32
#define S4		16
#define S3		8
#define S2		4
#define S1		2

#define LSH				12													// LPF SHift coefficient for level measurement
volatile uint32_t dsp_rssi, dsp_vox;										// Signal levels for IF and Audio ADC channels (fixed point 16.16)
int get_sval(void)
{
	uint32_t sval = GET_RSSI_LEVEL;											// Make local copy to prevent access glitches
	if (sval>S940) return(94);												// Return max 2 digits!
	if (sval>S930) return(93);
	if (sval>S920) return(92);
	if (sval>S910) return(91);
	if (sval>S9)   return(9);
	if (sval>S8)   return(8);
	if (sval>S7)   return(7);
	if (sval>S6)   return(6);
	if (sval>S5)   return(5);
	if (sval>S4)   return(4);
	if (sval>S3)   return(3);
	if (sval>S2)   return(2);
	return(1);
}

/*
 * AGC reference level is log2(0x40) = 6, where 0x40 is the MSB of half DAC_RANGE
 * 1/AGC_DECAY and 1/AGC_ATTACK are multipliers before agc_gain value integrator
 * These values should ultimately be set by the HMI.
 * The time it takes to a gain change is the ( (Set time)/(signal delta) ) / samplerate
 * So when delta is 1, and attack is 64, the time is 64/15625 = 4msec (fast attack)
 * The decay time is about 100x this value
 * Slow attack would be about 4096
 */
#define AGC_REF		6
#define AGC_DECAY	8192
#define AGC_SHORT	64
#define AGC_LONG	4096
#define AGC_DIS		32766
#define IFAGC_TOP	1023
#define RXAGC_TOP	2047
#define TXAGC_TOP	2047
volatile uint16_t agc_decay  = AGC_DIS;
volatile uint16_t agc_attack = AGC_DIS;

void dsp_setagc(int agc)
{
	switch(agc)
	{
	case AGC_SLOW:
		agc_attack = AGC_LONG;
		agc_decay  = AGC_DECAY;
		break;
	case AGC_FAST:
		agc_attack = AGC_SHORT;
		agc_decay  = AGC_DECAY;
		break;
	default:
		agc_attack = AGC_DIS;
		agc_decay  = AGC_DIS;
		break;
	}
}



/*
 * VOX LINGER is the number msec to wait before releasing TX mode
 * The level of detection is derived from the maximum ADC range.
 */
#define VOX_LINGER		500													// 500msec

volatile uint16_t vox_count = 0;											// Linger time in # of samples
volatile uint16_t vox_level = 0;											// ADC_BIAS is maximum amplitude from ADC
volatile bool	  vox_active;												// Is set when audio energy > vox level (and not OFF)
void dsp_setvox(int vox)
{
	switch(vox)
	{
	case VOX_HIGH:
		vox_level = ADC_BIAS/2;
		break;
	case VOX_MEDIUM:
		vox_level = ADC_BIAS/4;
		break;
	case VOX_LOW:
		vox_level = ADC_BIAS/16;
		break;
	default: 
		vox_level = 0;
		vox_count = 0;
		break;
	}
}


/*** Some handy macro's ***/

#define ABS(x)		( (x)<0   ? -(x) : (x) )
 
/*
 * Calculation of vector length:
 * Z = alpha*max(i,q) + beta*min(i,q); 
 * alpha = 1/1, beta = 3/8 (error<6.8%)
 * alpha = 15/16, beta = 15/32 (error<6.25%)
 * Better algorithm:
 * Z = max( max(i,q), alpha*max(i,q)+beta*min(i,q) )
 * alpha = 29/32, beta = 61/128 (error<2.4%)
 */
inline uint16_t mag(int16_t i, int16_t q)
{
	i = ABS(i); q = ABS(q);
	if (i>q)
		return (MAX(i,((29*i/32) + (61*q/128))));
	else
		return (MAX(q,((29*q/32) + (61*i/128))));
}

/* 
 * Note: A simple regression IIR single pole low pass filter could be made for anti-aliasing.
 *  y(n) = (1-a)*y(n-1) + a*x(n) = y(n-1) + a*(x(n) - y(n-1))
 * in this a = T / (T + R*C)  
 * Example:
 *    T is sample period (e.g. 64usec) 
 *    RC the desired RC time: T*(1-a)/a.
 *    example: a=1/256 : RC = 255*64usec = 16msec (65Hz)
 * Alternative faster implementation with higher accuracy
 *  y(n) = y(n-1) + (x(n) - y(n-1)>>b)
 * Here the filtered value is maintained in higher accuracy, i.e. left shifted by b bits.
 * Before using the value shift it back: y >> b. 
 * Also, for RC value 1/a = 1<<b, or RC = ((1<<b)-1)*64us  (if 64us is sample interval)
 */



/*** Include the desired DSP engine ***/

#if DSP_FFT == 1
#include "dsp_fft.c"
#else
#include "dsp_tim.c"
#endif



/** CORE1: DMA IRQ handler **/
/*
 * The IRQ handling is redirected to a DMA channel
 * This will transfer ADC_INT samples per channel, ADC_INT maximum is 10 (would take 60usec) but safer to use 8
 * These are all registers used for the sample acquisition process
 * A sample is a value between 0..4095, in a 16 bit unsigned integer
 * The DC bias value is somewhere around 2048, but will depend on the analogue circuits
 * The DC bias value is stored left shifted (by 16 as 32bit unsigned integer), to maintain precision
 */
 
// From RP2040 datasheet, DMA Status/Control register layout
// 0x80000000 [31]    : AHB_ERROR (0): Logical OR of the READ_ERROR and WRITE_ERROR flags
// 0x40000000 [30]    : READ_ERROR (0): If 1, the channel received a read bus error
// 0x20000000 [29]    : WRITE_ERROR (0): If 1, the channel received a write bus error
// 0x01000000 [24]    : BUSY (0): This flag goes high when the channel starts a new transfer sequence, and low when the...
// 0x00800000 [23]    : SNIFF_EN (0): If 1, this channel's data transfers are visible to the sniff hardware, and each...
// 0x00400000 [22]    : BSWAP (0): Apply byte-swap transformation to DMA data
// 0x00200000 [21]    : IRQ_QUIET (0): In QUIET mode, the channel does not generate IRQs at the end of every transfer block
// 0x001f8000 [20:15] : TREQ_SEL (0): Select a Transfer Request signal
// 0x00007800 [14:11] : CHAIN_TO (0): When this channel completes, it will trigger the channel indicated by CHAIN_TO
// 0x00000400 [10]    : RING_SEL (0): Select whether RING_SIZE applies to read or write addresses
// 0x000003c0 [9:6]   : RING_SIZE (0): Size of address wrap region
// 0x00000020 [5]     : INCR_WRITE (0): If 1, the write address increments with each transfer
// 0x00000010 [4]     : INCR_READ (0): If 1, the read address increments with each transfer
// 0x0000000c [3:2]   : DATA_SIZE (0): Set the size of each bus transfer (byte/halfword/word)
// 0x00000002 [1]     : HIGH_PRIORITY (0): HIGH_PRIORITY gives a channel preferential treatment in issue scheduling: in...
// 0x00000001 [0]     : EN (0): DMA Channel Enable

// 0x00120027 (IRQ_QUIET=0x0, TREQ_SEL=0x24, CHAIN_TO=0, INCR_WRITE=1, INCR_READ=0, DATA_SIZE=1, HIGH_PRIORITY=1, EN=1)	

/*
 * The dma_handler is called when the sample buffer adc_sample[][] is full.
 * It only stops the ADC conversions and resets DMA interrupt flag, samples are processed in timeout dsp_callback routine.
 */
#define CH0			0
#define DMA_CTRL0	0x00120027
volatile int      adccnt = 0;												// Sampling overflow indicator, negative when timeout is too early
void __not_in_flash_func(dma_handler)(void)
{
	adc_run(false);															// Stop freerunning ADC
	dma_hw->ints0 = 1u << CH0;												// Clear the interrupt request.
	adccnt++;																// ADC overrun indicator increment
	//while (!adc_fifo_is_empty()) adc_fifo_get();							// Empty leftovers from fifo
}



/** CORE1: Timer callback routine **/
/*
 * This runs every TIM_US, i.e. 64usec, and hence this determines the effective sample rate
 * The ADC is free running, nr of samples is limited by the attached DMA (ADC_INT per ADC channel)
 * One ADC cycle takes 6usec to complete (2usec per channel), times ADC_INT. 
 * So max ADC_INT depth is about 10, disregarding the time needed in this routine, so choose a lower value.
 * The ADC result is saved after processing the raw samples, so a new ADC burst can be started. 
 * Also the DACs are written with the next output sample, either A or I&Q channels.
 * The timing is critical, it assumes that the ADC is finished, so:
 * --> do not put any other stuff in this callback routine that may affect timing!
 */

#define ADC_INT		6														// Nr of samples for integration (use 8=2^3)
#define BSH			8														// Bias SHift size for the moving average; length is  2^BSH
#define DC_LEN		(1<<BSH)												// Length of DC level delay line (initial values: ADC_BIAS)
#define SUM_BIAS	(ADC_BIAS*DC_LEN)										// Sum of samples in delay line (initially DC_LEN*ADC_BIAS)
#define MED_LEN		3														// Median filter length
volatile uint16_t adc_sample[ADC_INT][3];									// ADC sample buffers, filled by DMA (one per channel)
volatile uint16_t adc_movavg[DC_LEN][3];									// ADC DC level running average sample delay lines
volatile uint32_t adc_sumbias[3] = {SUM_BIAS, SUM_BIAS, SUM_BIAS};			// ADC dynamic bias (DC) level, summed delay line
volatile uint16_t adc_bias[3] = {ADC_BIAS, ADC_BIAS, ADC_BIAS};				// ADC dynamic bias (DC) level
volatile int16_t  adc_result[3];											// Pre-processed sample, for each channel
volatile int      adc_k = 0;												// Points into lowpass delay line
volatile uint16_t if_agc = 1, rx_agc = 1, tx_agc = 1;						// Factor as level adjustment (IF, RX audio, TX audio)

semaphore_t dsp_sem;														// Semaphore to trigger dsp loop
repeating_timer_t dsp_timer;												// TIM_US timer
bool __not_in_flash_func(dsp_callback)(repeating_timer_t *t) 				// Timer callback routine
{
	int32_t temp;
	
	/** The call-rate of this function = resulting sample rate: S_RATE=1/TIM_US, --> 15625Hz **/

	// Integration and DC bias removal
	// Adds ADC_INT samples for each channel, after first removing DC bias
	//    this implicitly converts from unsigned to signed int 
	// Summaton increases dynamic range and has implicit LPF (but it may be better to use proper filter coefficients)
	adc_result[CH_Q] = 0;
	adc_result[CH_I] = 0;
	adc_result[CH_A] = 0;
	for (temp = 0; temp<ADC_INT; temp++)
	{
		adc_result[CH_Q] += (int16_t)(adc_sample[temp][CH_Q]) - adc_bias[CH_Q];
		adc_result[CH_I] += (int16_t)(adc_sample[temp][CH_I]) - adc_bias[CH_I];
		adc_result[CH_A] += (int16_t)(adc_sample[temp][CH_A]) - adc_bias[CH_A];
	}
	
	// Low pass filtering for adc_bias, based on running average.
	// Store sample history in movavg, sumbias = SUM(movavg[]), length of movavg is 2^BSH so bias = sumbias>>BSH
	// Calculate new bias / sumbias values and replace sample in movavg delay line
	adc_sumbias[CH_Q] += adc_sample[0][CH_Q] - adc_movavg[adc_k][CH_Q]; adc_bias[CH_Q] = adc_sumbias[CH_Q]>>BSH;
	adc_sumbias[CH_I] += adc_sample[0][CH_I] - adc_movavg[adc_k][CH_I]; adc_bias[CH_I] = adc_sumbias[CH_I]>>BSH;
	adc_sumbias[CH_A] += adc_sample[0][CH_A] - adc_movavg[adc_k][CH_A]; adc_bias[CH_A] = adc_sumbias[CH_A]>>BSH;
	adc_movavg[adc_k][CH_Q] = adc_sample[0][CH_Q];
	adc_movavg[adc_k][CH_I] = adc_sample[0][CH_I];
	adc_movavg[adc_k][CH_A] = adc_sample[0][CH_A];
	if (++adc_k >= DC_LEN) adc_k = 0;

	// Raw samples are no longer used, so kick-off a new ADC acquisition phase
	// Restart the ADCs and the DMA channel
	adc_select_input(0);													// Start with ADC0
	while (!adc_fifo_is_empty()) adc_fifo_get();							// Empty leftovers from fifo, if any
	dma_hw->ch[CH0].read_addr = (io_rw_32)&adc_hw->fifo;					// DMA: Read from ADC FIFO
	dma_hw->ch[CH0].write_addr = (io_rw_32)&adc_sample[0][0];				// DMA: Write to sample buffer
	dma_hw->ch[CH0].transfer_count = ADC_INT * 3;							// DMA: Nr of 16 bit words to transfer
	dma_hw->ch[CH0].ctrl_trig = DMA_CTRL0;									// DMA: Write ctrl word while starting the DMA
	adc_run(true);															// Start the ADC too
	adccnt--;																// ADC overrun indicator decrement	
	
	/*
	 * To be done for noise suppression:
	 * Add I-Q adc results to median delay line
	 * Calculate amplitude and add to delay line
	 * Choose median amplitude entry for further processing  
	 */
	 
	// Derive RSSI level from IF sample vector length
	// This value is taken through an IIR low-pass filter: 
	//   y(n) = y(n-1) + (x(n) - y(n-1)>>b)
	//   RC = ((1<<b)-1)*64us
	//   Before using the value: y >> b. 
	// Then determine IF AGC wrt to top level
	if (!tx_enabled)	
	{
		temp = mag(adc_result[CH_I], adc_result[CH_Q]);						// Approximate amplitude, with alpha max + beta min function
		temp = (MAX(1,temp));											    // Prevent 0 level
		temp = (temp<<16) - dsp_rssi;										// Promote amplitude to Q16.16 and calculate delta
		dsp_rssi += temp>>LSH;												// LPF: RC = (1<<LSH - 1) * 64usec (i.e. 0.26sec)
/*** This is meant to scale the IF signal. Fairly crude mechanism, should react slower. ***/
		if (IFAGC_TOP/GET_RSSI_LEVEL > if_agc )
			if_agc++;														// Increment factor when signal smaller than desired
		else
			if_agc--;														// Decrement when larger
		if (if_agc==0) if_agc=1;											// Should never happen
	}
	
	// Likewise, derive VOX level from Audio sample amplitude
	temp = ABS(adc_result[CH_A]);											// Take absolute amplitude 
	temp = (MAX(1,temp));												    // Prevent 0 level
	temp = (temp<<16) - dsp_vox;											// Promote to fixed point format (Q16.16), calculate delta
	dsp_vox += temp>>LSH;													// LPF: RC = (1<<LSH - 1) * 64usec
	tx_agc = TXAGC_TOP/GET_DSP_VOX;											// Calculate scaling factor (max level/actual level)
	if (tx_agc==0) tx_agc=1;												// Shouldn't ever happen
		
#if DSP_FFT == 1

	// Copy samples from/to the FFT buffers
	if (tx_enabled)
	{								
		A_buf[dsp_active][dsp_tick] = (int16_t)(tx_agc*adc_result[CH_A]);	// Copy A sample to A buffer
		pwm_set_gpio_level(DAC_I, I_buf[dsp_active][dsp_tick] + DAC_BIAS);	// Output I to DAC
		pwm_set_gpio_level(DAC_Q, Q_buf[dsp_active][dsp_tick] + DAC_BIAS);	// Output Q to DAC
	}
	else
	{
		I_buf[dsp_active][dsp_tick] = (int16_t)(if_agc*adc_result[CH_I]);	// Copy I sample to I buffer
		Q_buf[dsp_active][dsp_tick] = (int16_t)(if_agc*adc_result[CH_Q]);	// Copy Q sample to Q buffer

/*** ==> Need to insert RX_AGC mechanism here ***/

		pwm_set_gpio_level(DAC_A, A_buf[dsp_active][dsp_tick] + DAC_BIAS);	// Output A to DAC
	}
	
	// When buffers are full, move pointer to the next and signal the DSP loop
	if (++dsp_tick >= BUFSIZE)												// Increment tick and check range
	{
		dsp_overrun++;														// Increment overrun counter
		dsp_tick = 0;														// Reset counter
		if (++dsp_active > 2) dsp_active = 0;								// Point to next buffer
		sem_release(&dsp_sem);												// Signal background processing
	}
	
#else

	// Copy samples from/to the right buffers
	if (tx_enabled)
	{
		a_sample = tx_agc * adc_result[CH_A];								// Store A sample for background processing
		pwm_set_gpio_level(DAC_I, i_sample);								// Output calculated I sample to DAC
		pwm_set_gpio_level(DAC_Q, q_sample);								// Output calculated Q sample to DAC
	}
	else
	{							
		q_sample = rx_agc * adc_result[CH_Q];								// Store Q sample for background processing
		i_sample = rx_agc * adc_result[CH_I];								// Store I sample for background processing
		pwm_set_gpio_level(DAC_A, a_sample);								// Output calculated A sample to DAC
	}
	dsp_overrun++;															// Increment overrun counter
	sem_release(&dsp_sem);													// Signal background processing

#endif
		

	return true;
}


/** CORE1: DSP loop **/
/*
 * Background signal processing, triggered by semaphore dsp_sem
 * --> In Time Domain processing this is released every sample collection slot (64 us),
 * --> In Frequency Domain processing this is triggered when buffers are switched (64*512 us) 
 * This loop also initializes all signal processing variables
 */
void __not_in_flash_func(dsp_loop)()
{
	alarm_pool_t *ap;
	int i;
	
	tx_enabled = false;	
	vox_active = false;
	
	/* 
	 * Initialize DACs, 
	 * default mode is free running, 
	 * A and B pins are output 
	 */
	gpio_set_function(DAC_Q, GPIO_FUNC_PWM);								// GP20 is PWM for Q DAC (Slice 2, Channel A)
	gpio_set_function(DAC_I, GPIO_FUNC_PWM);								// GP21 is PWM for I DAC (Slice 2, Channel B)
	dac_iq = pwm_gpio_to_slice_num(DAC_Q);									// Get PWM slice for GP20 (Same for GP21)
	pwm_set_clkdiv_int_frac (dac_iq, 1, 0);									// clock divide by 1: full system clock
	pwm_set_wrap(dac_iq, DAC_RANGE-1);										// Set cycle length; nr of counts until wrap, i.e. 125/DAC_RANGE MHz
	pwm_set_enabled(dac_iq, true); 											// Set the PWM running
	
	gpio_set_function(DAC_A, GPIO_FUNC_PWM);								// GP22 is PWM for Audio DAC (Slice 3, Channel A)
	dac_audio = pwm_gpio_to_slice_num(DAC_A);								// Find PWM slice for GP22
	pwm_set_clkdiv_int_frac (dac_audio, 1, 0);								// clock divide by 1: full system clock
	pwm_set_wrap(dac_audio, DAC_RANGE-1);									// Set cycle length; nr of counts until wrap, i.e. 125/DAC_RANGE MHz
	pwm_set_enabled(dac_audio, true); 										// Set the PWM running

	/* 
	 * Initialize ADCs, use in round robin mode (3 channels)
	 * samples are stored in array through IRQ callback
	 * Initialize ADC delay lines for DC moving average
	 */
	adc_init();																// Initialize ADC to known state
	adc_gpio_init(ADC_Q);													// ADC GPIO for Q channel
	adc_gpio_init(ADC_I);													// ADC GPIO for I channel
	adc_gpio_init(ADC_A);													// ADC GPIO for Audio channel
	adc_set_round_robin(0x01+0x02+0x04);									// Sequence ADC 0-1-2 (GP 26, 27, 28) free running
	adc_select_input(0);													// Start with ADC0
	adc_fifo_setup(true,true,3,false,false);								// IRQ result, DMA req, fifo thr=3: xfer per 3 x 16 bits
	adc_set_clkdiv(0);														// Fastest clock (500 kSps)
	for (i=0; i<DC_LEN; i++)
	{
		adc_movavg[i][CH_Q] = ADC_BIAS;
		adc_movavg[i][CH_I] = ADC_BIAS;
		adc_movavg[i][CH_A] = ADC_BIAS;
	}

	/*
	 * Setup and start DMA channel CH0
	 */
	dma_channel_set_irq0_enabled(CH0, true);								// Raise IRQ line 0 when the channel finishes a block
	irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);						// Install IRQ handler
	irq_set_enabled(DMA_IRQ_0, true);										// Enable it
	irq_set_priority(DMA_IRQ_0, PICO_HIGHEST_IRQ_PRIORITY);					// Prevent race condition with timer
	
	dma_hw->ch[CH0].read_addr = (io_rw_32)&adc_hw->fifo;					// Read from ADC FIFO
	dma_hw->ch[CH0].write_addr = (io_rw_32)&adc_sample[0][0];				// Write to sample buffer
	dma_hw->ch[CH0].transfer_count = ADC_INT * 3;							// Nr of 16 bit words to transfer (interrupt when done)
	dma_hw->ch[CH0].ctrl_trig = DMA_CTRL0;									// Write ctrl word and start the DMA

	adc_run(true);															// Also start the ADC

	
	/*
	 * Use alarm_pool_add_repeating_timer_us() for a core1 associated timer
	 * First create an alarm pool on core1:
	 * alarm_pool_t *alarm_pool_create( uint hardware_alarm_num, 
	 *                                  uint max_timers);
	 * For the core1 alarm pool don't use the default alarm_num (usually 3) but e.g. 1
	 * Timer callback signals semaphore, while loop blocks on getting it.
	 * Initialize repeating timer on core1:
	 * bool alarm_pool_add_repeating_timer_us( alarm_pool_t *pool, 
	 *                                         int64_t delay_us, 
	 *                                         repeating_timer_callback_t callback, 
	 *                                         void *user_data, 
	 *                                         repeating_timer_t *out);
	 */
	sem_init(&dsp_sem, 0, 1);
	ap = alarm_pool_create(1, 4);
	alarm_pool_add_repeating_timer_us( ap, -TIM_US, dsp_callback, NULL, &dsp_timer);

	dsp_overrun = 0;
	
	// Background processing loop
    while(1) 
	{
		sem_acquire_blocking(&dsp_sem);										// Wait until timer-callback releases sem

		// Compare actual level with set threshold
		if (vox_level == 0)													// When VOX is disabled
		{
			vox_active = false;												//  always de-activate VOX trigger
			vox_count = 0;													//  and reset linger counter
		}
		else																// VOX is enabled
		{
			if ((GET_DSP_VOX) > vox_level)									// AND actual level > limit level
			{
#if DSP_FFT == 1
				vox_count = (S_RATE * VOX_LINGER / 1000)/512;				//  audio present, set linger counter
#else
				vox_count = S_RATE * VOX_LINGER / 1000;						//  audio present, set linger counter
#endif
				vox_active = true;											//  activate VOX trigger 
			}
			else if (vox_active)											// no audio but vox still active 
				if (--vox_count==0) vox_active = false;						//  deactivate VOX trigger when linger counter expires
				
		}


		if (tx_enabled)														// Use previous setting
		{
			gpio_put(GP_PTT_OUT, true); 									// Drive PTT high (active)  
			tx();															// Do TX signal processing (Freq or Time domain)
		}
		else
		{
			gpio_put(GP_PTT_OUT, false);									// Drive PTT low (inactive)   
			rx();															// Do RX signal processing (Freq or Time domain)
		}
		
		/** Activate transmission **/
		tx_enabled = vox_active || ptt_active;								// VOX or PTT triggered

		dsp_overrun--;														// Decrement overrun counter
		
#if DSP_FFT == 1
		dsp_tickx = dsp_tick;												// Capture how far we are in sampling a FFT buffer
#endif
	}
}




/** CORE0: Initialize dsp context and spawn CORE1 process **/
void dsp_init() 
{
    bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_PROC1_BITS; 				// Set Core 1 prio on bus to high
	multicore_launch_core1(dsp_loop);										// Start processing on Core 1
}






================================================
FILE: dsp.h
================================================
#ifndef __DSP_FFT_H__
#define __DSP_FFT_H__
/* 
 * dsp.h
 *
 * Created: Mar 2021
 * Author: Arjan te Marvelde
 *
 * See dsp.c for more information 
 *
 * HERE THE SELECTION BETWEEN TIME OR FREQUENCY DOMAIN PROCESSING IS MADE
 * DO THIS BY SETTING THE #define DSP_FFT TO 0 OR TO 1 RESPECTIVELY
 *
 */


/* 
 * Callback timeout is TIM_US, value in usec
 * The carrier offset is !=0 only in FFT case.
 */
 
#if DSP_FFT == 1

#define TIM_US		   64
#define S_RATE		15625					// 1e6/TIM_US
#define FC_OFFSET	 3906  					// RX carrier in bin FFT_SIZE/4 ==> S_RATE/4

#else
	
#define TIM_US		   64
#define S_RATE		15625					// 1e6/TIM_US
#define FC_OFFSET 	    0					// Must be 0 for time-domain DSP

#endif


/** DSP module interface **/

extern volatile uint32_t dsp_rssi, dsp_vox;	// Fixed point UQ16.16
#define GET_RSSI_LEVEL	(uint16_t)(dsp_rssi>>16)
#define GET_DSP_VOX		(uint16_t)(dsp_vox>>16)
int get_sval(void);

extern volatile bool tx_enabled;			// Determined by (vox_active || ptt_active)

#define VOX_OFF			0
#define VOX_LOW			1
#define VOX_MEDIUM		2
#define VOX_HIGH		3
void dsp_setvox(int vox);

#define MODE_USB		0
#define MODE_LSB		1
#define MODE_AM			2
#define MODE_CW			3
void dsp_setmode(int mode);

#define AGC_NONE		0
#define AGC_SLOW		1
#define AGC_FAST		2
void dsp_setagc(int agc);

void dsp_init();

#endif


================================================
FILE: dsp_fft.c
================================================
/*
 * dsp_fft.c
 * ==>TO BE INCLUDED IN dsp.c
 *
 * Created: May 2022
 * Author: Arjan te Marvelde
 * 
 * Signal processing of RX and TX branch, to be run on the second processor core (CORE1).
 * A branch has a dedicated routine that must run on set times.
 * In this case it runs when half FFT_SIZE of samples is ready to be processed.
 *
 *
 * The pace for sampling is set by a timer at 64usec (15.625 kHz)
 * The associated timer callback routine:
 * - handles data transfer to/from physical interfaces
 * - starts a new ADC conversion sequence 
 * - maintains dsp_tick counter
 * - when dsp_tick == FFT_SIZE/2 (one buffer), the dsp-loop is triggered.
 *
 * The ADC functions in round-robin and fifo mode, triggering IRQ after 3 conversions (ADC[0..2])
 * The ADC FIFO IRQ handler reads the 3 samples from the fifo after stopping the ADC
 *
 * Buffer structure, built from half FFT_SIZE buffers.
 * The I, Q and A external interfaces communicate each through 3x buffers.
 * One buffer is being filled or emptied, depending on data direction.
 * The other two are swapped with the FFT signal processing buffers.
 * Since we use complex FFT, the algorithm uses 4x buffers.
 *
 * I, Q and A buffers are used as queues. RX case looks like:
 *
 *        +--+--+--+                                   +--+--+--+
 *  i --> |  |  |  |                                   |  |  |  | --> a
 *        +--+--+--+                                   +--+--+--+
 *            \  \  \     +--+--+                     /  /
 *             ---------> |  |  |                    /  /
 *                        +--+--+    FFT-DSP-iFFT ------
 *             ---------> |  |  |                    
 *            /  /  /     +--+--+
 *        +--+--+--+
 *  q --> |  |  |  |
 *        +--+--+--+
 *
 * RX, when triggered by timer callback:
 * - The oldest two I and Q buffers are copied into the FFT buffers
 * - FFT is executed
 * - Signal processing is done
 * - iFFT is executed
 * - The oldest real FFT buffer is moved to the A output queue
 *
 *        +--+--+--+                                   +--+--+--+
 *  a --> |  |  |  |                                   |  |  |  | --> i
 *        +--+--+--+                                   +--+--+--+
 *            \  \  \     +--+--+                     /  /
 *              --------> |  |  |                 -------
 *                        +--+--+    FFT-DSP-iFFT
 *                        |  |  |                 -------
 *                        +--+--+                     \  \
 *                                                     +--+--+--+
 *                                                     |  |  |  | --> q
 *                                                     +--+--+--+
 *
 * TX, when triggered by timer callback:
 * - The oldest two A buffers are copied to the real FFT buffer, the imaginary FFT buffer is nulled
 * - FFT is executed
 * - Signal processing is done
 * - iFFT is executed
 * - The oldest FFT buffers are appended to the I/Q output queues
 *
 * The bin step is the sampling frequency divided by the FFT_SIZE.
 * So for S_RATE=15625 and FFT_SIZE=1024 this step is 15625/1024=15.259 Hz
 * The Subcarrier offset (Fc) is at about half the Nyquist frequency: bin 256 or 3906 Hz
 *
 */

#include "uSDR.h"
#include "dsp.h"

/*
 * FFT buffer allocation
 * Buffer size is FFT_SIZE/2 (see fix_fft.h).
 * In case FFT_SIZE of 1024, a buffer is 1kB
 *  RX:  3 buffers for I samples, 3 buffers for Q samples, 3 buffers for Audio
 *  DSP: 4 buffers for FFT, complex samples and these have to be consecutive!
 *  TX:  re-use RX buffers in reverse order
 * Total of 13kByte RAM is required.
 * Samples are 16 bit signed integer, but align buffers on 32bit boundaries
 * dsp_tick points into I, Q and A buffers, so wrap once per two FFTs
 * When tick==FFT_SIZE/2: do buffer copy
 */ 
#define BUFSIZE		FFT_SIZE/2
int16_t  I_buf[3][BUFSIZE] __attribute__((aligned(4)));						// I sample queue, 3x buffer of FFT_SIZE/2
int16_t  Q_buf[3][BUFSIZE] __attribute__((aligned(4)));						// Q sample queue, 3x buffer of FFT_SIZE/2
int16_t  A_buf[3][BUFSIZE] __attribute__((aligned(4)));						// A sample queue, 3x buffer of FFT_SIZE/2
int16_t XI_buf[FFT_SIZE]   __attribute__((aligned(4)));						// Re FFT buffer, 1x buffer of FFT_SIZE
int16_t XQ_buf[FFT_SIZE]   __attribute__((aligned(4)));						// Im FFT buffer, 1x buffer of FFT_SIZE

// Sample buffer indexes, updated by timer callback
volatile int      dsp_active = 0;											// I, Q, A active buffer number (0..2)
volatile uint32_t dsp_tick   = 0;											// Index in active buffer
volatile uint32_t dsp_tickx  = 0;											// Load indicator DSP loop

// Spectrum bins for a frequency
#define BIN(f)			(int)(((f)*FFT_SIZE+S_RATE/2)/S_RATE)
#define BIN_FC			  256												// Use BIN_FC > BIN_3000 to avoid aliasing!
#define BIN_100       	    7												//  110Hz bin
#define BIN_300		 	   20												//  300Hz bin
#define BIN_900		 	   59												//  900Hz bin
#define BIN_3000		  197												// 3000Hz bin
#define BIN_3600          236												// 3600Hz bin


/*
 * Downshift frequency with Fs/4 = Fc
 * SEE: Lyons, Understanding DSP, CHAPTER 13.1.2
 *
 * Shift center frequency back to DC by multipling time domain samples with e(-j*w*t)
 * w = 2*pi*f, where f is FC_OFFSET (3906Hz)
 * t = n*Ts, where Ts is 1/S_RATE (1/15625Hz)
 * So the exponent becomes n*2*pi*FC_OFFSET/S_RATE = n*pi/2 (since FC_OFFSET = S_RATE/4)
 * The complex offset is then cos(-n*pi/2) + j*sin(-n*pi/2) ==> (a,b) = ( 1, 0); ( 0,-1); (-1, 0); ( 0, 1); ... 
 * Complex multiply: (a+jb)*(I+jQ)=(aI-bQ) + j(aQ+bI)       ==> (I,Q) = ( I, Q); ( Q,-I); (-I,-Q); (-Q, I); ...
 */
void __not_in_flash_func(dsp_shift)(void) 
{
	int i;
	uint16_t x;
	
	for (i=0; i<FFT_SIZE; i+=4)
	{
		x = XI_buf[i+1];
		XI_buf[i+1] = XQ_buf[i+1];
		XQ_buf[i+1] = -x;
		XI_buf[i+2] = -XI_buf[i+2];
		XQ_buf[i+2] = -XQ_buf[i+2];
		x = XI_buf[i+3];
		XI_buf[i+3] = -XQ_buf[i+3];
		XQ_buf[i+3] = x;
	}
}

/*
 * NOTE THAT FLTERING SHOULD REALLY BE DONE BY MULTIPLY WITH FFT OF FILTER IMPULSE RESPONSE
 * SEE: The Scientist and Engineer's Guide to Digital Signal Processing, CHAPTER 18
 *
 * This applies a bandpass filter to XI and XQ buffers
 * lowbin and highbin edges must be between 3 and FFT_SIZE/2 - 3
 * Edge is a 7 bin raised cosine flank, i.e. 100Hz wide
 * Coefficients are: 0, 0.067, 0.25, 0.5, 0.75, 0.933, 1
 *    where the edge bin is in the center of this flank
 * Note: maybe make slope less steep, e.g. 9 or 11 bins 
 *   ____                      ____
 * _/USB0\____________________/LSB0\_
 * [-------|-------][-------|-------]
 * ^                ^               ^
 * 0                BUFSIZE         FFTSIZE
 *
 * The parameter sidebands determines whether LSB (-1) USB (+1) or DSB(0) is passed.
 */
#define DSP_PASS_LSB	-1
#define DSP_PASS_USB	 1
#define DSP_PASS_DSB	 0
void __not_in_flash_func(dsp_bandpass)(int lowbin, int highbin, int sidebands)
{
	int i, lo1, lo2, hi1, hi2;
	
	if ((lowbin<3)||(highbin>(FFT_SIZE/2-3))||(highbin-lowbin<6)) return;
	
	// Boundaries are inclusive
	lo1 = lowbin-2; 
	lo2 = highbin+2;
	hi1 = FFT_SIZE-highbin-2; 
	hi2 = FFT_SIZE-lowbin+2;

	// Null all bins excluded from passbands
	// Calculate filter edges as raised cosine
	XI_buf[0] = 0; XQ_buf[0] = 0; 											// Block DC
	
	for (i=1; i<lo1; i++)													// Block until low filter side
		{ XI_buf[i] = 0; XQ_buf[i] = 0; }

	if (sidebands==DSP_PASS_LSB)
	{
		for (i=lo1; i<lo2; i++) 											// LSB only: block USB bins
			{ XI_buf[i] = 0; XQ_buf[i] = 0; }
	}
	else 																	// USB or DSB: apply filter curve
	{
		i=lo1;
		XI_buf[i] = XI_buf[i]*0.067; XQ_buf[i] = XQ_buf[i]*0.067; i++;
		XI_buf[i] = XI_buf[i]*0.250; XQ_buf[i] = XQ_buf[i]*0.250; i++;
		XI_buf[i] = XI_buf[i]*0.500; XQ_buf[i] = XQ_buf[i]*0.500; i++;
		XI_buf[i] = XI_buf[i]*0.750; XQ_buf[i] = XQ_buf[i]*0.750; i++;
		XI_buf[i] = XI_buf[i]*0.933; XQ_buf[i] = XQ_buf[i]*0.933; 
		i=lo2;
		XI_buf[i] = XI_buf[i]*0.067; XQ_buf[i] = XQ_buf[i]*0.067; i--;
		XI_buf[i] = XI_buf[i]*0.250; XQ_buf[i] = XQ_buf[i]*0.250; i--;
		XI_buf[i] = XI_buf[i]*0.500; XQ_buf[i] = XQ_buf[i]*0.500; i--;
		XI_buf[i] = XI_buf[i]*0.750; XQ_buf[i] = XQ_buf[i]*0.750; i--;
		XI_buf[i] = XI_buf[i]*0.933; XQ_buf[i] = XQ_buf[i]*0.933;
	}
	for (i=lo2+1; i<hi1; i++)												// Block unused negative freq bins
		{ XI_buf[i] = 0; XQ_buf[i] = 0; }

	if (sidebands==DSP_PASS_USB)
	{
		for (i=hi1; i<hi2; i++) 											// USB only: block LSB bins
		{ XI_buf[i] = 0; XQ_buf[i] = 0; }
	}
	else																	// LSB or DSB: apply filter curve
	{
		i=hi1;
		XI_buf[i] = XI_buf[i]*0.067; XQ_buf[i] = XQ_buf[i]*0.067; i++;
		XI_buf[i] = XI_buf[i]*0.250; XQ_buf[i] = XQ_buf[i]*0.250; i++;
		XI_buf[i] = XI_buf[i]*0.500; XQ_buf[i] = XQ_buf[i]*0.500; i++;
		XI_buf[i] = XI_buf[i]*0.750; XQ_buf[i] = XQ_buf[i]*0.750; i++;
		XI_buf[i] = XI_buf[i]*0.933; XQ_buf[i] = XQ_buf[i]*0.933; 
		i=hi2;
		XI_buf[i] = XI_buf[i]*0.067; XQ_buf[i] = XQ_buf[i]*0.067; i--;
		XI_buf[i] = XI_buf[i]*0.250; XQ_buf[i] = XQ_buf[i]*0.250; i--;
		XI_buf[i] = XI_buf[i]*0.500; XQ_buf[i] = XQ_buf[i]*0.500; i--;
		XI_buf[i] = XI_buf[i]*0.750; XQ_buf[i] = XQ_buf[i]*0.750; i--;
		XI_buf[i] = XI_buf[i]*0.933; XQ_buf[i] = XQ_buf[i]*0.933;
	}
	for (i=hi2+1; i<FFT_SIZE; i++) 												// Block from high filter side
		{ XI_buf[i] = 0; XQ_buf[i] = 0; }
}



/** CORE1: RX branch **/
/*
 * Execute RX branch signal processing
 * max time to spend is <32ms (BUFSIZE*TIM_US)
 * The pre-processed I/Q samples are passed in I_BUF and Q_BUF
 * The calculated A samples are passed in A_BUF
 */
volatile int scale0;
volatile int scale1; 
bool __not_in_flash_func(rx)(void) 
{
	int b;
	int i;
	int16_t *ip, *qp, *ap, *xip, *xqp;
	int16_t peak;
		
	b = dsp_active;															// Point to Active sample buffer
	
	/*** Copy saved I/Q buffers to FFT filter buffer ***/
	if (++b > 2) b = 0;														// Point to Old Saved sample buffer
	ip = &I_buf[b][0]; xip = &XI_buf[0];
	qp = &Q_buf[b][0]; xqp = &XQ_buf[0];
	for (i=0; i<BUFSIZE; i++)
	{
		*xip++ = *ip++;
		*xqp++ = *qp++;
	}
	if (++b > 2) b = 0;														// Point to New Saved sample buffer
	ip = &I_buf[b][0]; xip = &XI_buf[BUFSIZE];
	qp = &Q_buf[b][0]; xqp = &XQ_buf[BUFSIZE];
	for (i=0; i<BUFSIZE; i++)
	{
		*xip++ = *ip++;
		*xqp++ = *qp++;
	}

	/*** Downshift time samples with FC_OFFSET ***/
	dsp_shift();															// In effect Fc moves to DC
	
	/*** Execute FFT ***/
	scale0 = fix_fft(&XI_buf[0], &XQ_buf[0], false);						// Conversion to frequency domain 
	
	/*** Filter sidebands ***/
	// At this point positive USB0 and LSB0 surround DC
	// [USB0---|---USB1][LSB1---|---LSB0]
	switch (dsp_mode)
	{
	case MODE_USB:
		// [USB0---|-------][-------|-------]
		dsp_bandpass(BIN_100, BIN_3000, DSP_PASS_USB);
		break;
	case MODE_LSB:
		// [-------|-------][-------|---LSB0]
		dsp_bandpass(BIN_100, BIN_3000, DSP_PASS_LSB);
		break;
	case MODE_AM:
		// [USB0---|-------][-------|---LSB0]
		dsp_bandpass(BIN_100, BIN_3000, DSP_PASS_DSB);
		break;
	case MODE_CW:
		// Bandpass CW, 600Hz
		dsp_bandpass(BIN_900-BIN_300, BIN_900+BIN_300, DSP_PASS_USB);
		break;
	}

	
	/*** Execute inverse FFT ***/
	scale1 = fix_fft(&XI_buf[0], &XQ_buf[0], true);


	/*** Export FFT buffer to A ***/
	b = dsp_active;															// Assume active buffer not changed, i.e. no overruns
	if (++b > 2) b = 0;														// Point to oldest (will be next for output)
	ap = &A_buf[b][0]; xip = &XI_buf[BUFSIZE];
	for (i=0; i<BUFSIZE; i++)
	{
		*ap++ = *xip++;														// Copy newest results (overlap-save method)
	}


	/*** Scale down into DAC_RANGE! ***/	
	peak = 256;
	for (i=0; i<BUFSIZE; i++)									
	{
		A_buf[b][i] /= peak;
	}
		
	return true;
}


/** CORE1: TX branch **/
/*
 * Execute TX branch signal processing
 * max time to spend is <32ms (BUFSIZE*TIM_US)
 * The pre-processed A samples are passed in A_BUF
 * The calculated I and Q samples are passed in I_BUF and Q_BUF
 */
bool __not_in_flash_func(tx)(void) 
{
	int b;
	int i;
	int16_t *ip, *qp, *ap, *xip, *xqp;
	int16_t peak;
		
	b = dsp_active;															// Point to Active sample buffer
	
	/*** Copy saved A buffers to FFT buffers, NULL Im. part ***/
	if (++b > 2) b = 0;														// Point to Old Saved sample buffer
	ap = &A_buf[b][0]; xip = &XI_buf[0];
	xqp = &XQ_buf[0];
	for (i=0; i<BUFSIZE; i++)
	{
		*xip++ = *ap++;
		*xqp++ = 0;
	}
	if (++b > 2) b = 0;														// Point to New Saved sample buffer
	ap = &A_buf[b][0]; xip = &XI_buf[BUFSIZE];
	xqp = &XQ_buf[BUFSIZE];
	for (i=0; i<BUFSIZE; i++)
	{
		*xip++ = *ap++;
		*xqp++ = 0;
	}

	
	/*** Execute FFT ***/
	scale0 = fix_fft(&XI_buf[0], &XQ_buf[0], false);	
	
	
	/*** Shift and filter sidebands ***/
	XI_buf[0] = 0; XQ_buf[0] = 0;											// Block DC
	switch (dsp_mode)
	{
	case MODE_USB:
		// Bandpass Audio, USB only
		dsp_bandpass(BIN_100, BIN_3000, 1);
		// Shift USB up to to Fc, assumes Fc > bandwidth
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[BIN_FC+i] = XI_buf[i];
			XQ_buf[BIN_FC+i] = XQ_buf[i];
			XI_buf[i] = 0;	
			XQ_buf[i] = 0;
		}
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[FFT_SIZE-BIN_FC-i] = XI_buf[BIN_FC+i];
			XQ_buf[FFT_SIZE-BIN_FC-i] = XQ_buf[BIN_FC+i];
		}
		break;
	case MODE_LSB:
		// Bandpass Audio, LSB only
		dsp_bandpass(BIN_100, BIN_3000, -1);
		// Shift LSB up to Fc
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[BIN_FC-i] = XI_buf[FFT_SIZE-i];
			XQ_buf[BIN_FC-i] = XQ_buf[FFT_SIZE-i];
			XI_buf[FFT_SIZE-i] = 0;
			XQ_buf[FFT_SIZE-i] = 0;
		}
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[FFT_SIZE-BIN_FC+i] = XI_buf[BIN_FC-i];
			XQ_buf[FFT_SIZE-BIN_FC+i] = XQ_buf[BIN_FC-i];
		}
		break;
	case MODE_AM:
		// Bandpass Audio
		dsp_bandpass(BIN_100, BIN_3000, 0);
		// Shift DSB up to Fc
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[BIN_FC+i] = XI_buf[i];
			XQ_buf[BIN_FC+i] = XQ_buf[i];
			XI_buf[i] = 0;	
			XQ_buf[i] = 0;
			XI_buf[BIN_FC-i] = XI_buf[FFT_SIZE-i];
			XQ_buf[BIN_FC-i] = XQ_buf[FFT_SIZE-i];
			XI_buf[FFT_SIZE-i] = 0;
			XQ_buf[FFT_SIZE-i] = 0;
		}
		for (i=1; i<BIN_3000; i++)
		{
			XI_buf[FFT_SIZE-BIN_FC-i] = XI_buf[BIN_FC+i];
			XQ_buf[FFT_SIZE-BIN_FC-i] = XQ_buf[BIN_FC+i];
			XI_buf[FFT_SIZE-BIN_FC+i] = XI_buf[BIN_FC-i];
			XQ_buf[FFT_SIZE-BIN_FC+i] = XQ_buf[BIN_FC-i];
		}
		break;
	case MODE_CW:

		// Create a carrier on 900Hz from Fc

		break;
	}

	
	/*** Execute inverse FFT ***/
	scale1 = fix_fft(&XI_buf[0], &XQ_buf[0], true);


	/*** Export FFT buffer to I and Q ***/
	b = dsp_active;															// Assume active buffer not changed, i.e. no overruns
	if (++b > 2) b = 0;														// Point to oldest (will be next for output)
	qp = &Q_buf[b][0]; xqp = &XQ_buf[BUFSIZE];
	ip = &I_buf[b][0]; xip = &XI_buf[BUFSIZE];
	for (i=0; i<BUFSIZE; i++)
	{
		*qp++ = *xqp++;														// Copy newest results (overlap-save method)
		*ip++ = *xip++;
	}


	/*** Scale down into DAC_RANGE! ***/	
	peak = 256;																// !!! Why 256 ???
	for (i=0; i<BUFSIZE; i++)									
	{
		Q_buf[b][i] /= peak;		
		I_buf[b][i] /= peak;
	}

	return true;
}







================================================
FILE: dsp_tim.c
================================================
/*
 * dsp_tim.c
 * ==>TO BE INCLUDED IN dsp.c
 *
 * Created: May 2022
 * Author: Arjan te Marvelde
 * 
 * Signal processing of RX and TX branch, to be run on the second processor core.
 * Each branch has a dedicated routine that must run on set times.
 * The period is determined by reads from the inter-core fifo, by the dsp_loop() routine. 
 * This fifo is written from core0 from a 16us timer callback routine (i.e. 62.5kHz)
 *
 * The RX branch:
 * - Sample I and Q QSD channels, and shift into I and Q delay line (62.5 kHz per channel)
 * - Low pass filter: Fc=4kHz
 * - Quarter rate (15.625 kHz) to improve low freq behavior of Hilbert transform
 * - Calculate 15 tap Hilbert transform on Q
 * - Demodulate, taking proper delays into account
 * - Push to Audio output DAC
 *
 * Always perform audio sampling (62.5kHz) and level detections, in case of VOX active
 *
 * The TX branch (if VOX or PTT):
 * - Low pass filter: Fc=3kHz
 * - Eight rate (7.8125 kHz) to improve low F behavior of Hilbert transform
 * - Generate Q samples by doing a Hilbert transform
 * - Push I and Q to QSE output DACs
 *
 */

#include "uSDR.h"


volatile int32_t q_sample, i_sample, a_sample;								// Latest processed sample values


/* 
 * Low pass FIR filters Fc=3, 7 and 15 kHz (see http://t-filter.engineerjs.com/)
 * Settings: sample rates 62500, 31250 or 15625 Hz, stopband -40dB, passband ripple 5dB
 * Note: 8 bit precision, so divide sum by 256 (this could be improved when 32bit accumulator)
 */
int16_t lpf3_62[15] =  {  3,  3,  5,  7,  9, 10, 11, 11, 11, 10,  9,  7,  5,  3,  3};	// Pass: 0-3000, Stop: 6000-31250
int16_t lpf3_31[15] =  { -2, -3, -3,  1, 10, 21, 31, 35, 31, 21, 10,  1, -3, -3, -2};	// Pass: 0-3000, Stop: 6000-15625
int16_t lpf3_15[15] =  {  3,  4, -3,-14,-15,  6, 38, 53, 38,  6,-15,-14, -3,  4,  3};	// Pass: 0-3000, Stop: 4500-7812
int16_t lpf7_62[15] =  { -2, -1,  1,  7, 16, 26, 33, 36, 33, 26, 16,  7,  1, -1, -2};	// Pass: 0-7000, Stop: 10000-31250
int16_t lpf7_31[15] =  { -1,  4,  9,  2,-12, -2, 40, 66, 40, -2,-12,  2,  9,  4, -1};	// Pass: 0-7000, Stop: 10000-15625
int16_t lpf15_62[15] = { -1,  3, 12,  6,-12, -4, 40, 69, 40, -4,-12,  6, 12,  3, -1};	// Pass: 0-15000, Stop: 20000-31250




/** CORE1: RX Branch **/

/* 
 * Execute RX branch signal processing
 * max time to spend is <64us (TIM_US)
 * The pre-processed I/Q samples are passed in i_sample and q_sample
 * The calculated A sample is passed in a_sample
 */
volatile int32_t i_s_raw[15], q_s_raw[15];									// Raw I/Q samples minus DC bias
volatile int32_t i_s[15], q_s[15];											// Filtered I/Q samples
bool __not_in_flash_func(rx)(void) 
{
	int32_t q_accu, i_accu;
	int32_t qh;
	uint16_t i;
	
	/*** SAMPLING ***/
	/* 
	 * Shift-in I and Q raw samples 
	 */
	for (i=0; i<14; i++)													// Store preprocessed samples in shift registers
	{
		q_s_raw[i] = q_s_raw[i+1];
		i_s_raw[i] = i_s_raw[i+1];
	}
	q_s_raw[14] = q_sample;
	i_s_raw[14] = i_sample;
	
	
	/*
	 * Low pass FIR filter
	 */
	q_accu = 0;																// Initialize accumulators
	i_accu = 0;
	for (i=0; i<15; i++)													// Low pass FIR filter
	{
		q_accu += (int32_t)q_s_raw[i]*lpf3_15[i];							// Fc=3kHz, at 15625 Hz sampling		
		i_accu += (int32_t)i_s_raw[i]*lpf3_15[i];							// Fc=3kHz, at 15625 Hz sampling	
	}
	q_accu = q_accu/256;
	i_accu = i_accu/256;
	
	for (i=0; i<14; i++) 													// Store filtered samples in shift registers
	{
		q_s[i] = q_s[i+1];
		i_s[i] = i_s[i+1];
	}
	q_s[14] = q_accu;
	i_s[14] = i_accu;
	

	/*** DEMODULATION ***/
	switch (dsp_mode)
	{
	case MODE_USB:
		/* 
		 * USB demodulate: I[7] - Qh,
		 * Qh is Classic Hilbert transform 15 taps, 12 bits 
		 * (see Iowa Hills calculator)
		 */	
		q_accu = (q_s[0]-q_s[14])*315L + (q_s[2]-q_s[12])*440L + 
		         (q_s[4]-q_s[10])*734L + (q_s[6]-q_s[ 8])*2202L;
		qh = q_accu / 4096L;	
		a_sample = i_s[7] - qh;
		break;
	case MODE_LSB:
		/* 
		 * LSB demodulate: I[7] + Qh,
		 * Qh is Classic Hilbert transform 15 taps, 12 bits 
		 * (see Iowa Hills calculator)
		 */	
		q_accu = (q_s[0]-q_s[14])*315L + (q_s[2]-q_s[12])*440L + 
		         (q_s[4]-q_s[10])*734L + (q_s[6]-q_s[ 8])*2202L;
		qh = q_accu / 4096L;	
		a_sample = i_s[7] + qh;
		break;
	case MODE_AM:
		/*
		 * AM demodulate: sqrt(sqr(i)+sqr(q))
		 * Approximated with mag(i,q)
		 */
		a_sample = mag(i_s[7], q_s[7]);
		break;
	default:
		break;
	}
	
	/*** AUDIO GENERATION ***/

	/*
	 * Scale and clip output,  
	 * Send to audio DAC output
	 */
	a_sample = (a_sample/64) + DAC_BIAS;									// -18dB and add bias level
	if (a_sample > DAC_RANGE)												// Clip to DAC range
		a_sample = DAC_RANGE;
	else if (a_sample<0)
		a_sample = 0;

	return true;
}


/** CORE1: TX branch **/
/*
 * Execute TX branch signal processing, 
 * max time to spend is <64us (TIM_US)
 * The pre-processed audio sample is passed in a_sample
 * The calculated I and Q samples are passed in i_sample and q_sample
 */
volatile int16_t a_s_raw[15]; 												// Raw samples, minus DC bias
volatile int16_t a_s[15];													// Filtered and decimated samplesvolatile int16_t 
bool __not_in_flash_func(tx)(void) 
{
	int32_t a_accu, q_accu;
	int16_t qh;
	int i;
	uint16_t i_dac, q_dac;
		
	/*** RAW Audio ***/
	for (i=0; i<14; i++) 													//   and store in shift register
		a_s_raw[i] = a_s_raw[i+1];
	a_s_raw[14] = a_sample;
	
	/*** Low pass filter ***/
	a_accu = 0;																// Initialize accumulator
	for (i=0; i<15; i++)													// Low pass FIR filter, using raw samples
		a_accu += (int32_t)a_s_raw[i]*lpf3_15[i];							//   Fc=3kHz, at 15.625 kHz sampling		
		
	for (i=0; i<14; i++) 													// Shift decimated samples
		a_s[i] = a_s[i+1];
	a_s[14] = a_accu / 256;													// Store rescaled accumulator

	/*** MODULATION ***/
	switch (dsp_mode)
	{
	case 0:																	// USB
		/* 
		 * qh is Classic Hilbert transform 15 taps, 12 bits 
		 * (see Iowa Hills calculator)
		 */	
		q_accu = (a_s[0]-a_s[14])*315L + (a_s[2]-a_s[12])*440L + 
		         (a_s[4]-a_s[10])*734L + (a_s[6]-a_s[ 8])*2202L;
		qh = -(q_accu / 4096L);												// USB: sign is negative
		break;
	case 1:																	// LSB
		/* 
		 * qh is Classic Hilbert transform 15 taps, 12 bits 
		 * (see Iowa Hills calculator)
		 */	
		q_accu = (a_s[0]-a_s[14])*315L + (a_s[2]-a_s[12])*440L + 
		         (a_s[4]-a_s[10])*734L + (a_s[6]-a_s[ 8])*2202L;
		qh = q_accu / 4096L;												// LSB: sign is positive
		break;
	case 2:																	// AM
		/*
		 * I and Q values are identical
		 */
		qh = a_s[7];
		break;
	default:
		break;
	}

	/* 
	 * Write I and Q to QSE DACs, phase is 7 samples back.
	 * Need to multiply AC with DAC_RANGE/ADC_RANGE (appr 1/8)
	 * Any case: clip to range
	 */
	a_accu = DAC_BIAS - (qh/8);
	if (a_accu<0)
		q_sample = 0;
	else if (a_accu>(DAC_RANGE-1))
		q_sample = DAC_RANGE-1;
	else
		q_sample = a_accu;
	
	a_accu = DAC_BIAS + (a_s[7]/8);
	if (a_accu<0)
		i_sample = 0;
	else if (a_accu>(DAC_RANGE-1))
		i_sample = DAC_RANGE-1;
	else
		i_sample = a_accu;
		
	
	return true;
}





================================================
FILE: fix_fft.c
================================================
/* fix_fft.c - Fixed-point in-place DIT Fast Fourier Transform  */
/*
  All data are fixed-point uint16_t integers, in which -32768
  to +32768 represent -1.0 to +1.0 respectively. Integer
  arithmetic is used for speed, instead of the more natural
  floating-point.

  For the forward FFT (time -> freq), fixed scaling is
  performed to prevent arithmetic overflow, and to map a 0dB
  sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
  coefficients. The return value is always 0.

  For the inverse FFT (freq -> time), fixed scaling cannot be
  done, as two 0dB coefficients would sum to a peak amplitude
  of 64K, overflowing the 32k range of the fixed-point integers.
  Thus, the fix_fft() routine performs variable scaling, and
  returns a value which is the number of bits LEFT by which
  the output must be shifted to get the actual amplitude
  (i.e. if fix_fft() returns 3, each value of fr[] and fi[]
  must be multiplied by 8 (2**3) for proper scaling.
  Clearly, this cannot be done within fixed-point uint16_t
  integers. In practice, if the result is to be used as a
  filter, the scale_shift can usually be ignored, as the
  result will be approximately correctly normalized as is.

  Written by:  Tom Roberts  11/8/89
  Made portable:  Malcolm Slaney 12/15/94 malcolm@interval.com
  Enhanced:  Dimitrios P. Bouras  14 Jun 2006 dbouras@ieee.org
*/
/*
  This implementation uses a lookup table for bit reverse sorting,
  which adds 2kbyte to the memory footprint.
  The iFFT range detector has been optimized.
  The bitshifting of signed integers is undefined, so these have been
  replaced by divisions. The compiler will optimize it.
  The size is fixed at 1024.
*/

#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/platform.h"
#include "fix_fft.h"


/** Fixed point Sine lookup table, [-1, 1] == [-32768, 32767] **/
int16_t Sine[3*FFT_SIZE/4] =
{
	    0,    201,    402,    603,    804,   1005,   1206,   1406,
	 1607,   1808,   2009,   2209,   2410,   2610,   2811,   3011,
	 3211,   3411,   3611,   3811,   4011,   4210,   4409,   4608,
	 4807,   5006,   5205,   5403,   5601,   5799,   5997,   6195,
	 6392,   6589,   6786,   6982,   7179,   7375,   7571,   7766,
	 7961,   8156,   8351,   8545,   8739,   8932,   9126,   9319,
	 9511,   9703,   9895,  10087,  10278,  10469,  10659,  10849,
	11038,  11227,  11416,  11604,  11792,  11980,  12166,  12353,
	12539,  12724,  12909,  13094,  13278,  13462,  13645,  13827,
	14009,  14191,  14372,  14552,  14732,  14911,  15090,  15268,
	15446,  15623,  15799,  15975,  16150,  16325,  16499,  16672,
	16845,  17017,  17189,  17360,  17530,  17699,  17868,  18036,
	18204,  18371,  18537,  18702,  18867,  19031,  19194,  19357,
	19519,  19680,  19840,  20000,  20159,  20317,  20474,  20631,
	20787,  20942,  21096,  21249,  21402,  21554,  21705,  21855,
	22004,  22153,  22301,  22448,  22594,  22739,  22883,  23027,
	23169,  23311,  23452,  23592,  23731,  23869,  24006,  24143,
	24278,  24413,  24546,  24679,  24811,  24942,  25072,  25201,
	25329,  25456,  25582,  25707,  25831,  25954,  26077,  26198,
	26318,  26437,  26556,  26673,  26789,  26905,  27019,  27132,
	27244,  27355,  27466,  27575,  27683,  27790,  27896,  28001,
	28105,  28208,  28309,  28410,  28510,  28608,  28706,  28802,
	28897,  28992,  29085,  29177,  29268,  29358,  29446,  29534,
	29621,  29706,  29790,  29873,  29955,  30036,  30116,  30195,
	30272,  30349,  30424,  30498,  30571,  30643,  30713,  30783,
	30851,  30918,  30984,  31049,  31113,  31175,  31236,  31297,
	31356,  31413,  31470,  31525,  31580,  31633,  31684,  31735,
	31785,  31833,  31880,  31926,  31970,  32014,  32056,  32097,
	32137,  32176,  32213,  32249,  32284,  32318,  32350,  32382,
	32412,  32441,  32468,  32495,  32520,  32544,  32567,  32588,
	32609,  32628,  32646,  32662,  32678,  32692,  32705,  32717,
	32727,  32736,  32744,  32751,  32757,  32761,  32764,  32766,
	32767,  32766,  32764,  32761,  32757,  32751,  32744,  32736,
	32727,  32717,  32705,  32692,  32678,  32662,  32646,  32628,
	32609,  32588,  32567,  32544,  32520,  32495,  32468,  32441,
	32412,  32382,  32350,  32318,  32284,  32249,  32213,  32176,
	32137,  32097,  32056,  32014,  31970,  31926,  31880,  31833,
	31785,  31735,  31684,  31633,  31580,  31525,  31470,  31413,
	31356,  31297,  31236,  31175,  31113,  31049,  30984,  30918,
	30851,  30783,  30713,  30643,  30571,  30498,  30424,  30349,
	30272,  30195,  30116,  30036,  29955,  29873,  29790,  29706,
	29621,  29534,  29446,  29358,  29268,  29177,  29085,  28992,
	28897,  28802,  28706,  28608,  28510,  28410,  28309,  28208,
	28105,  28001,  27896,  27790,  27683,  27575,  27466,  27355,
	27244,  27132,  27019,  26905,  26789,  26673,  26556,  26437,
	26318,  26198,  26077,  25954,  25831,  25707,  25582,  25456,
	25329,  25201,  25072,  24942,  24811,  24679,  24546,  24413,
	24278,  24143,  24006,  23869,  23731,  23592,  23452,  23311,
	23169,  23027,  22883,  22739,  22594,  22448,  22301,  22153,
	22004,  21855,  21705,  21554,  21402,  21249,  21096,  20942,
	20787,  20631,  20474,  20317,  20159,  20000,  19840,  19680,
	19519,  19357,  19194,  19031,  18867,  18702,  18537,  18371,
	18204,  18036,  17868,  17699,  17530,  17360,  17189,  17017,
	16845,  16672,  16499,  16325,  16150,  15975,  15799,  15623,
	15446,  15268,  15090,  14911,  14732,  14552,  14372,  14191,
	14009,  13827,  13645,  13462,  13278,  13094,  12909,  12724,
	12539,  12353,  12166,  11980,  11792,  11604,  11416,  11227,
	11038,  10849,  10659,  10469,  10278,  10087,   9895,   9703,
	 9511,   9319,   9126,   8932,   8739,   8545,   8351,   8156,
	 7961,   7766,   7571,   7375,   7179,   6982,   6786,   6589,
	 6392,   6195,   5997,   5799,   5601,   5403,   5205,   5006,
	 4807,   4608,   4409,   4210,   4011,   3811,   3611,   3411,
	 3211,   3011,   2811,   2610,   2410,   2209,   2009,   1808,
	 1607,   1406,   1206,   1005,    804,    603,    402,    201,
	    0,   -201,   -402,   -603,   -804,  -1005,  -1206,  -1406,
    -1607,  -1808,  -2009,  -2209,  -2410,  -2610,  -2811,  -3011,
    -3211,  -3411,  -3611,  -3811,  -4011,  -4210,  -4409,  -4608,
    -4807,  -5006,  -5205,  -5403,  -5601,  -5799,  -5997,  -6195,
    -6392,  -6589,  -6786,  -6982,  -7179,  -7375,  -7571,  -7766,
    -7961,  -8156,  -8351,  -8545,  -8739,  -8932,  -9126,  -9319,
    -9511,  -9703,  -9895, -10087, -10278, -10469, -10659, -10849,
   -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
   -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
   -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
   -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
   -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
   -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
   -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
   -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
   -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
   -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
   -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
   -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
   -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
   -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
   -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
   -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
   -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
   -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
   -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
   -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
   -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
   -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
   -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
   -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
   -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766
};


static int16_t bitrev[FFT_SIZE] =
{
	0x000, 0x200, 0x100, 0x300, 0x080, 0x280, 0x180, 0x380, 0x040, 0x240, 0x140, 0x340, 0x0c0, 0x2c0, 0x1c0, 0x3c0,
	0x020, 0x220, 0x120, 0x320, 0x0a0, 0x2a0, 0x1a0, 0x3a0, 0x060, 0x260, 0x160, 0x360, 0x0e0, 0x2e0, 0x1e0, 0x3e0,
	0x010, 0x210, 0x110, 0x310, 0x090, 0x290, 0x190, 0x390, 0x050, 0x250, 0x150, 0x350, 0x0d0, 0x2d0, 0x1d0, 0x3d0,
	0x030, 0x230, 0x130, 0x330, 0x0b0, 0x2b0, 0x1b0, 0x3b0, 0x070, 0x270, 0x170, 0x370, 0x0f0, 0x2f0, 0x1f0, 0x3f0,
	0x008, 0x208, 0x108, 0x308, 0x088, 0x288, 0x188, 0x388, 0x048, 0x248, 0x148, 0x348, 0x0c8, 0x2c8, 0x1c8, 0x3c8,
	0x028, 0x228, 0x128, 0x328, 0x0a8, 0x2a8, 0x1a8, 0x3a8, 0x068, 0x268, 0x168, 0x368, 0x0e8, 0x2e8, 0x1e8, 0x3e8,
	0x018, 0x218, 0x118, 0x318, 0x098, 0x298, 0x198, 0x398, 0x058, 0x258, 0x158, 0x358, 0x0d8, 0x2d8, 0x1d8, 0x3d8,
	0x038, 0x238, 0x138, 0x338, 0x0b8, 0x2b8, 0x1b8, 0x3b8, 0x078, 0x278, 0x178, 0x378, 0x0f8, 0x2f8, 0x1f8, 0x3f8,
	0x004, 0x204, 0x104, 0x304, 0x084, 0x284, 0x184, 0x384, 0x044, 0x244, 0x144, 0x344, 0x0c4, 0x2c4, 0x1c4, 0x3c4,
	0x024, 0x224, 0x124, 0x324, 0x0a4, 0x2a4, 0x1a4, 0x3a4, 0x064, 0x264, 0x164, 0x364, 0x0e4, 0x2e4, 0x1e4, 0x3e4,
	0x014, 0x214, 0x114, 0x314, 0x094, 0x294, 0x194, 0x394, 0x054, 0x254, 0x154, 0x354, 0x0d4, 0x2d4, 0x1d4, 0x3d4,
	0x034, 0x234, 0x134, 0x334, 0x0b4, 0x2b4, 0x1b4, 0x3b4, 0x074, 0x274, 0x174, 0x374, 0x0f4, 0x2f4, 0x1f4, 0x3f4,
	0x00c, 0x20c, 0x10c, 0x30c, 0x08c, 0x28c, 0x18c, 0x38c, 0x04c, 0x24c, 0x14c, 0x34c, 0x0cc, 0x2cc, 0x1cc, 0x3cc,
	0x02c, 0x22c, 0x12c, 0x32c, 0x0ac, 0x2ac, 0x1ac, 0x3ac, 0x06c, 0x26c, 0x16c, 0x36c, 0x0ec, 0x2ec, 0x1ec, 0x3ec,
	0x01c, 0x21c, 0x11c, 0x31c, 0x09c, 0x29c, 0x19c, 0x39c, 0x05c, 0x25c, 0x15c, 0x35c, 0x0dc, 0x2dc, 0x1dc, 0x3dc,
	0x03c, 0x23c, 0x13c, 0x33c, 0x0bc, 0x2bc, 0x1bc, 0x3bc, 0x07c, 0x27c, 0x17c, 0x37c, 0x0fc, 0x2fc, 0x1fc, 0x3fc,
	0x002, 0x202, 0x102, 0x302, 0x082, 0x282, 0x182, 0x382, 0x042, 0x242, 0x142, 0x342, 0x0c2, 0x2c2, 0x1c2, 0x3c2,
	0x022, 0x222, 0x122, 0x322, 0x0a2, 0x2a2, 0x1a2, 0x3a2, 0x062, 0x262, 0x162, 0x362, 0x0e2, 0x2e2, 0x1e2, 0x3e2,
	0x012, 0x212, 0x112, 0x312, 0x092, 0x292, 0x192, 0x392, 0x052, 0x252, 0x152, 0x352, 0x0d2, 0x2d2, 0x1d2, 0x3d2,
	0x032, 0x232, 0x132, 0x332, 0x0b2, 0x2b2, 0x1b2, 0x3b2, 0x072, 0x272, 0x172, 0x372, 0x0f2, 0x2f2, 0x1f2, 0x3f2,
	0x00a, 0x20a, 0x10a, 0x30a, 0x08a, 0x28a, 0x18a, 0x38a, 0x04a, 0x24a, 0x14a, 0x34a, 0x0ca, 0x2ca, 0x1ca, 0x3ca,
	0x02a, 0x22a, 0x12a, 0x32a, 0x0aa, 0x2aa, 0x1aa, 0x3aa, 0x06a, 0x26a, 0x16a, 0x36a, 0x0ea, 0x2ea, 0x1ea, 0x3ea,
	0x01a, 0x21a, 0x11a, 0x31a, 0x09a, 0x29a, 0x19a, 0x39a, 0x05a, 0x25a, 0x15a, 0x35a, 0x0da, 0x2da, 0x1da, 0x3da,
	0x03a, 0x23a, 0x13a, 0x33a, 0x0ba, 0x2ba, 0x1ba, 0x3ba, 0x07a, 0x27a, 0x17a, 0x37a, 0x0fa, 0x2fa, 0x1fa, 0x3fa,
	0x006, 0x206, 0x106, 0x306, 0x086, 0x286, 0x186, 0x386, 0x046, 0x246, 0x146, 0x346, 0x0c6, 0x2c6, 0x1c6, 0x3c6,
	0x026, 0x226, 0x126, 0x326, 0x0a6, 0x2a6, 0x1a6, 0x3a6, 0x066, 0x266, 0x166, 0x366, 0x0e6, 0x2e6, 0x1e6, 0x3e6,
	0x016, 0x216, 0x116, 0x316, 0x096, 0x296, 0x196, 0x396, 0x056, 0x256, 0x156, 0x356, 0x0d6, 0x2d6, 0x1d6, 0x3d6,
	0x036, 0x236, 0x136, 0x336, 0x0b6, 0x2b6, 0x1b6, 0x3b6, 0x076, 0x276, 0x176, 0x376, 0x0f6, 0x2f6, 0x1f6, 0x3f6,
	0x00e, 0x20e, 0x10e, 0x30e, 0x08e, 0x28e, 0x18e, 0x38e, 0x04e, 0x24e, 0x14e, 0x34e, 0x0ce, 0x2ce, 0x1ce, 0x3ce,
	0x02e, 0x22e, 0x12e, 0x32e, 0x0ae, 0x2ae, 0x1ae, 0x3ae, 0x06e, 0x26e, 0x16e, 0x36e, 0x0ee, 0x2ee, 0x1ee, 0x3ee,
	0x01e, 0x21e, 0x11e, 0x31e, 0x09e, 0x29e, 0x19e, 0x39e, 0x05e, 0x25e, 0x15e, 0x35e, 0x0de, 0x2de, 0x1de, 0x3de,
	0x03e, 0x23e, 0x13e, 0x33e, 0x0be, 0x2be, 0x1be, 0x3be, 0x07e, 0x27e, 0x17e, 0x37e, 0x0fe, 0x2fe, 0x1fe, 0x3fe,
	0x001, 0x201, 0x101, 0x301, 0x081, 0x281, 0x181, 0x381, 0x041, 0x241, 0x141, 0x341, 0x0c1, 0x2c1, 0x1c1, 0x3c1,
	0x021, 0x221, 0x121, 0x321, 0x0a1, 0x2a1, 0x1a1, 0x3a1, 0x061, 0x261, 0x161, 0x361, 0x0e1, 0x2e1, 0x1e1, 0x3e1,
	0x011, 0x211, 0x111, 0x311, 0x091, 0x291, 0x191, 0x391, 0x051, 0x251, 0x151, 0x351, 0x0d1, 0x2d1, 0x1d1, 0x3d1,
	0x031, 0x231, 0x131, 0x331, 0x0b1, 0x2b1, 0x1b1, 0x3b1, 0x071, 0x271, 0x171, 0x371, 0x0f1, 0x2f1, 0x1f1, 0x3f1,
	0x009, 0x209, 0x109, 0x309, 0x089, 0x289, 0x189, 0x389, 0x049, 0x249, 0x149, 0x349, 0x0c9, 0x2c9, 0x1c9, 0x3c9,
	0x029, 0x229, 0x129, 0x329, 0x0a9, 0x2a9, 0x1a9, 0x3a9, 0x069, 0x269, 0x169, 0x369, 0x0e9, 0x2e9, 0x1e9, 0x3e9,
	0x019, 0x219, 0x119, 0x319, 0x099, 0x299, 0x199, 0x399, 0x059, 0x259, 0x159, 0x359, 0x0d9, 0x2d9, 0x1d9, 0x3d9,
	0x039, 0x239, 0x139, 0x339, 0x0b9, 0x2b9, 0x1b9, 0x3b9, 0x079, 0x279, 0x179, 0x379, 0x0f9, 0x2f9, 0x1f9, 0x3f9,
	0x005, 0x205, 0x105, 0x305, 0x085, 0x285, 0x185, 0x385, 0x045, 0x245, 0x145, 0x345, 0x0c5, 0x2c5, 0x1c5, 0x3c5,
	0x025, 0x225, 0x125, 0x325, 0x0a5, 0x2a5, 0x1a5, 0x3a5, 0x065, 0x265, 0x165, 0x365, 0x0e5, 0x2e5, 0x1e5, 0x3e5,
	0x015, 0x215, 0x115, 0x315, 0x095, 0x295, 0x195, 0x395, 0x055, 0x255, 0x155, 0x355, 0x0d5, 0x2d5, 0x1d5, 0x3d5,
	0x035, 0x235, 0x135, 0x335, 0x0b5, 0x2b5, 0x1b5, 0x3b5, 0x075, 0x275, 0x175, 0x375, 0x0f5, 0x2f5, 0x1f5, 0x3f5,
	0x00d, 0x20d, 0x10d, 0x30d, 0x08d, 0x28d, 0x18d, 0x38d, 0x04d, 0x24d, 0x14d, 0x34d, 0x0cd, 0x2cd, 0x1cd, 0x3cd,
	0x02d, 0x22d, 0x12d, 0x32d, 0x0ad, 0x2ad, 0x1ad, 0x3ad, 0x06d, 0x26d, 0x16d, 0x36d, 0x0ed, 0x2ed, 0x1ed, 0x3ed,
	0x01d, 0x21d, 0x11d, 0x31d, 0x09d, 0x29d, 0x19d, 0x39d, 0x05d, 0x25d, 0x15d, 0x35d, 0x0dd, 0x2dd, 0x1dd, 0x3dd,
	0x03d, 0x23d, 0x13d, 0x33d, 0x0bd, 0x2bd, 0x1bd, 0x3bd, 0x07d, 0x27d, 0x17d, 0x37d, 0x0fd, 0x2fd, 0x1fd, 0x3fd,
	0x003, 0x203, 0x103, 0x303, 0x083, 0x283, 0x183, 0x383, 0x043, 0x243, 0x143, 0x343, 0x0c3, 0x2c3, 0x1c3, 0x3c3,
	0x023, 0x223, 0x123, 0x323, 0x0a3, 0x2a3, 0x1a3, 0x3a3, 0x063, 0x263, 0x163, 0x363, 0x0e3, 0x2e3, 0x1e3, 0x3e3,
	0x013, 0x213, 0x113, 0x313, 0x093, 0x293, 0x193, 0x393, 0x053, 0x253, 0x153, 0x353, 0x0d3, 0x2d3, 0x1d3, 0x3d3,
	0x033, 0x233, 0x133, 0x333, 0x0b3, 0x2b3, 0x1b3, 0x3b3, 0x073, 0x273, 0x173, 0x373, 0x0f3, 0x2f3, 0x1f3, 0x3f3,
	0x00b, 0x20b, 0x10b, 0x30b, 0x08b, 0x28b, 0x18b, 0x38b, 0x04b, 0x24b, 0x14b, 0x34b, 0x0cb, 0x2cb, 0x1cb, 0x3cb,
	0x02b, 0x22b, 0x12b, 0x32b, 0x0ab, 0x2ab, 0x1ab, 0x3ab, 0x06b, 0x26b, 0x16b, 0x36b, 0x0eb, 0x2eb, 0x1eb, 0x3eb,
	0x01b, 0x21b, 0x11b, 0x31b, 0x09b, 0x29b, 0x19b, 0x39b, 0x05b, 0x25b, 0x15b, 0x35b, 0x0db, 0x2db, 0x1db, 0x3db,
	0x03b, 0x23b, 0x13b, 0x33b, 0x0bb, 0x2bb, 0x1bb, 0x3bb, 0x07b, 0x27b, 0x17b, 0x37b, 0x0fb, 0x2fb, 0x1fb, 0x3fb,
	0x007, 0x207, 0x107, 0x307, 0x087, 0x287, 0x187, 0x387, 0x047, 0x247, 0x147, 0x347, 0x0c7, 0x2c7, 0x1c7, 0x3c7,
	0x027, 0x227, 0x127, 0x327, 0x0a7, 0x2a7, 0x1a7, 0x3a7, 0x067, 0x267, 0x167, 0x367, 0x0e7, 0x2e7, 0x1e7, 0x3e7,
	0x017, 0x217, 0x117, 0x317, 0x097, 0x297, 0x197, 0x397, 0x057, 0x257, 0x157, 0x357, 0x0d7, 0x2d7, 0x1d7, 0x3d7,
	0x037, 0x237, 0x137, 0x337, 0x0b7, 0x2b7, 0x1b7, 0x3b7, 0x077, 0x277, 0x177, 0x377, 0x0f7, 0x2f7, 0x1f7, 0x3f7,
	0x00f, 0x20f, 0x10f, 0x30f, 0x08f, 0x28f, 0x18f, 0x38f, 0x04f, 0x24f, 0x14f, 0x34f, 0x0cf, 0x2cf, 0x1cf, 0x3cf,
	0x02f, 0x22f, 0x12f, 0x32f, 0x0af, 0x2af, 0x1af, 0x3af, 0x06f, 0x26f, 0x16f, 0x36f, 0x0ef, 0x2ef, 0x1ef, 0x3ef,
	0x01f, 0x21f, 0x11f, 0x31f, 0x09f, 0x29f, 0x19f, 0x39f, 0x05f, 0x25f, 0x15f, 0x35f, 0x0df, 0x2df, 0x1df, 0x3df,
	0x03f, 0x23f, 0x13f, 0x33f, 0x0bf, 0x2bf, 0x1bf, 0x3bf, 0x07f, 0x27f, 0x17f, 0x37f, 0x0ff, 0x2ff, 0x1ff, 0x3ff
};


/** FIX_MPY() **/
/*
 * Assume Q(0,15) notation, 1 sign, 0 int, 15 frac bits
 */
int16_t __not_in_flash_func(FIX_MPY)(int16_t a, int16_t b)					// Fixed-point mpy and scaling
{
	int32_t c;

	c = (int32_t)a * (int32_t)b;											// multiply 
	c = c + 0x4000;															// and round up
	c = c >> 15;														    // Shift right fractional bits
	return((int16_t)c);													    // Return scaled product
}


/** FIX_FFT() **/
/*
 * fr[] 	i samples [1024]
 * fi[] 	q samples [1024]
 * inverse	true: iFFT
 * Note: i-FFT could also be calculated by exchanging the arrays for FFT (fxtbook.pdf 21.7)
 */
int __not_in_flash_func(fix_fft)(int16_t *fr, int16_t *fi, bool inverse)
{
	uint16_t i, j, m, k, step, scale;
	bool shift;
	int16_t qr, qi, tr, ti, wr, wi;
	int16_t *bp;

	/* Decimation in time: re-order samples */
	bp=&bitrev[0];
	for (i=0; i<FFT_SIZE; i++)
	{
		if (*bp > i)
		{
			tr = fr[i]; fr[i] = fr[*bp]; fr[*bp] = tr;
			ti = fi[i]; fi[i] = fi[*bp]; fi[*bp] = ti;
		}
		bp++;
	}


	scale = 0;
	step  = 1;																// Counting up: 1, 2, 4, 8, ...
	/* FFT Stages */
	for (k=FFT_ORDER; k>0; k--)                                             // #cycles: FFT_ORDER
	{
		/* Scaling
		 * Variable scaling, depends on current data
		 * --> it seems quite CPU intensive to go through complete array
		 *     FFT_ORDER times, could this be optimized?
		 * If always scaling:
		 * --> the main loop has log_2(FFT_SIZE) cycles,
		 *     resulting in an overall factor of 1/FFT_SIZE,
		 *     distributed over cycles to maximize accuracy.
		 */
        shift = false;														// No shift, unless...
        for (i=0; i<FFT_SIZE; ++i) 											// Range test all samples
        {
            if ((fr[i] > 0x3fff) || (fr[i] < -0x4000) || (fi[i] > 0x3fff) || (fi[i] < -0x4000))
            {
                shift = true;
                scale++;
                break;														// Bail out at first detect
            }
        }

		/* Inner loops resolving the butterflies for each stage*/
		for (m=0; m<step; m++) 											    // #cycles: step
		{
		    // Determine wiggle factors
			j = m << (k-1);													// 0 <= j < FFT_SIZE/2
			wr = Sine[j+FFT_SIZE/4];										// Real part, i.e. Cosine
			wi = inverse ? Sine[j] : -Sine[j];								// Imaginary part
			
			if (shift) { wr = wr/2; wi = wi/2; }							// Scale factors by 1/2

			for (i=m; i<FFT_SIZE; i+=(step*2))								// #cycles: FFT_SIZE/step
			{
				j = i + step;                                               // re-assign j !
				tr = FIX_MPY(wr,fr[j]) - FIX_MPY(wi,fi[j]);					// Complex multiply
				ti = FIX_MPY(wr,fi[j]) + FIX_MPY(wi,fr[j]);
				qr = shift ? fr[i]/2 : fr[i]; 
				qi = shift ? fi[i]/2 : fi[i]; 
				fr[i] = qr + tr;
				fi[i] = qi + ti;
				fr[j] = qr - tr;
				fi[j] = qi - ti;
			}																// #total: FFT_ORDER * step * FFT_SIZE/step
		}
		
		step = step<<1;
	}
	return scale;
}


#ifdef BLAH
// int16_t contains signed fixed point representation Q(2,14)
// 1 sign bit, 1 int bit and 14 frac bits
// precomputed value K represents 0.5
#define Q	14
#define K   (1 << (Q - 1))

// a + b
int16_t q_add(int16_t a, int16_t b)
{
    int32_t tmp;

    tmp = (int32_t)a + (int32_t)b;
	
    if (tmp > 0x7FFF) 														// Clip result
		tmp = 0x7FFF;
    else if (tmp < -0x8000) 
		tmp = -0x8000;

    return (int16_t)tmp;
}

// a - b
int16_t q_sub(int16_t a, int16_t b)
{
    return a - b;
}

// a * b
int16_t q_mul(int16_t a, int16_t b)
{
    int32_t tmp;

    tmp = (int32_t)a * (int32_t)b;
    tmp += K;    															// Rounding; mid values are rounded up
	tmp = tmp >> Q;    														// Correct by dividing by base
	
	if (tmp > 0x7FFF) 														// Clip result
		tmp = 0x7FFF;
	else if (tmp < -0x8000) 
		tmp = -0x8000;
	
	return (int16_t)tmp;
}

// a / b
int16_t q_div(int16_t a, int16_t b)
{
    int32_t tmp;

	tmp = (int32_t)a << Q;													// Pre multiply with base

    if ((tmp >= 0 && b >= 0) || (tmp < 0 && b < 0))  						// Rounding; mid values are rounded up 
        tmp += (b >> 2);
    else																	//  or down...
        tmp -= (b >> 2);

    return (int16_t)(tmp / b);
}
#endif


================================================
FILE: fix_fft.h
================================================
#ifndef __FIX_FFT_H__
#define __FIX_FFT_H__
/* 
 * fix_fft.h
 *
 * Created: Apr 2022
 * Author: Arjan te Marvelde
 *
 * See fix_fft.c for more information 
 */

#define FFT_SIZE	1024				// Use this for buffer allocations
#define FFT_ORDER	10					// FFT_SIZE = 1 << FFT_ORDER

int fix_fft(int16_t *fr, int16_t *fi, bool inverse);

#endif


================================================
FILE: font16.c
================================================
/**
  ******************************************************************************
  * @file    font16.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    18-February-2014
  * @brief   This file provides text font16 for STM32xx-EVAL's LCD driver. 
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "fonts.h"
// 
//  Font data for Courier New 12pt
// 

const unsigned char Font16_Table[] =
{
  // @0 ' ' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @32 '!' (11 pixels wide)
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @64 '"' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1D, 0xC0, //    ### ### 
  0x1D, 0xC0, //    ### ### 
  0x08, 0x80, //     #   #  
  0x08, 0x80, //     #   #  
  0x08, 0x80, //     #   #  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @96 '#' (11 pixels wide)
  0x00, 0x00, //            
  0x0D, 0x80, //     ## ##  
  0x0D, 0x80, //     ## ##  
  0x0D, 0x80, //     ## ##  
  0x0D, 0x80, //     ## ##  
  0x3F, 0xC0, //   ######## 
  0x1B, 0x00, //    ## ##   
  0x3F, 0xC0, //   ######## 
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @128 '$' (11 pixels wide)
  0x04, 0x00, //      #     
  0x1F, 0x80, //    ######  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x38, 0x00, //   ###      
  0x1E, 0x00, //    ####    
  0x0F, 0x00, //     ####   
  0x03, 0x80, //       ###  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x00, //   ######   
  0x04, 0x00, //      #     
  0x04, 0x00, //      #     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @160 '%' (11 pixels wide)
  0x00, 0x00, //            
  0x18, 0x00, //    ##      
  0x24, 0x00, //   #  #     
  0x24, 0x00, //   #  #     
  0x18, 0xC0, //    ##   ## 
  0x07, 0x80, //      ####  
  0x1E, 0x00, //    ####    
  0x31, 0x80, //   ##   ##  
  0x02, 0x40, //       #  # 
  0x02, 0x40, //       #  # 
  0x01, 0x80, //        ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @192 '&' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x0F, 0x00, //     ####   
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x0C, 0x00, //     ##     
  0x1D, 0x80, //    ### ##  
  0x37, 0x00, //   ## ###   
  0x33, 0x00, //   ##  ##   
  0x1D, 0x80, //    ### ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @224 ''' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x07, 0x00, //      ###   
  0x07, 0x00, //      ###   
  0x02, 0x00, //       #    
  0x02, 0x00, //       #    
  0x02, 0x00, //       #    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @256 '(' (11 pixels wide)
  0x00, 0x00, //            
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x06, 0x00, //      ##    
  0x0E, 0x00, //     ###    
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0E, 0x00, //     ###    
  0x06, 0x00, //      ##    
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @288 ')' (11 pixels wide)
  0x00, 0x00, //            
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x0C, 0x00, //     ##     
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x1C, 0x00, //    ###     
  0x18, 0x00, //    ##      
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @320 '*' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x3F, 0xC0, //   ######## 
  0x3F, 0xC0, //   ######## 
  0x0F, 0x00, //     ####   
  0x1F, 0x80, //    ######  
  0x19, 0x80, //    ##  ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @352 '+' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x04, 0x00, //      #     
  0x04, 0x00, //      #     
  0x04, 0x00, //      #     
  0x3F, 0x80, //   #######  
  0x04, 0x00, //      #     
  0x04, 0x00, //      #     
  0x04, 0x00, //      #     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @384 ',' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x04, 0x00, //      #     
  0x0C, 0x00, //     ##     
  0x08, 0x00, //     #      
  0x08, 0x00, //     #      
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @416 '-' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x3F, 0x80, //   #######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @448 '.' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @480 '/' (11 pixels wide)
  0x00, 0xC0, //         ## 
  0x00, 0xC0, //         ## 
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @512 '0' (11 pixels wide)
  0x00, 0x00, //            
  0x0E, 0x00, //     ###    
  0x1B, 0x00, //    ## ##   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1B, 0x00, //    ## ##   
  0x0E, 0x00, //     ###    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @544 '1' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x3E, 0x00, //   #####    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x3F, 0xC0, //   ######## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @576 '2' (11 pixels wide)
  0x00, 0x00, //            
  0x0F, 0x00, //     ####   
  0x19, 0x80, //    ##  ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x03, 0x00, //       ##   
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x18, 0x00, //    ##      
  0x30, 0x00, //   ##       
  0x3F, 0x80, //   #######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @608 '3' (11 pixels wide)
  0x00, 0x00, //            
  0x3F, 0x00, //   ######   
  0x61, 0x80, //  ##    ##  
  0x01, 0x80, //        ##  
  0x03, 0x00, //       ##   
  0x1F, 0x00, //    #####   
  0x03, 0x80, //       ###  
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x61, 0x80, //  ##    ##  
  0x3F, 0x00, //   ######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @640 '4' (11 pixels wide)
  0x00, 0x00, //            
  0x07, 0x00, //      ###   
  0x07, 0x00, //      ###   
  0x0F, 0x00, //     ####   
  0x0B, 0x00, //     # ##   
  0x1B, 0x00, //    ## ##   
  0x13, 0x00, //    #  ##   
  0x33, 0x00, //   ##  ##   
  0x3F, 0x80, //   #######  
  0x03, 0x00, //       ##   
  0x0F, 0x80, //     #####  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @672 '5' (11 pixels wide)
  0x00, 0x00, //            
  0x1F, 0x80, //    ######  
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x1F, 0x00, //    #####   
  0x11, 0x80, //    #   ##  
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x21, 0x80, //   #    ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @704 '6' (11 pixels wide)
  0x00, 0x00, //            
  0x07, 0x80, //      ####  
  0x1C, 0x00, //    ###     
  0x18, 0x00, //    ##      
  0x30, 0x00, //   ##       
  0x37, 0x00, //   ## ###   
  0x39, 0x80, //   ###  ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x19, 0x80, //    ##  ##  
  0x0F, 0x00, //     ####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @736 '7' (11 pixels wide)
  0x00, 0x00, //            
  0x7F, 0x00, //  #######   
  0x43, 0x00, //  #    ##   
  0x03, 0x00, //       ##   
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @768 '8' (11 pixels wide)
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @800 '9' (11 pixels wide)
  0x00, 0x00, //            
  0x1E, 0x00, //    ####    
  0x33, 0x00, //   ##  ##   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0x80, //    ### ##  
  0x01, 0x80, //        ##  
  0x03, 0x00, //       ##   
  0x07, 0x00, //      ###   
  0x3C, 0x00, //   ####     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @832 ':' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @864 ';' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x04, 0x00, //      #     
  0x08, 0x00, //     #      
  0x08, 0x00, //     #      
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @896 '<' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0xC0, //         ## 
  0x03, 0x00, //       ##   
  0x04, 0x00, //      #     
  0x18, 0x00, //    ##      
  0x60, 0x00, //  ##        
  0x18, 0x00, //    ##      
  0x04, 0x00, //      #     
  0x03, 0x00, //       ##   
  0x00, 0xC0, //         ## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @928 '=' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0xC0, //  ######### 
  0x00, 0x00, //            
  0x7F, 0xC0, //  ######### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @960 '>' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x60, 0x00, //  ##        
  0x18, 0x00, //    ##      
  0x04, 0x00, //      #     
  0x03, 0x00, //       ##   
  0x00, 0xC0, //         ## 
  0x03, 0x00, //       ##   
  0x04, 0x00, //      #     
  0x18, 0x00, //    ##      
  0x60, 0x00, //  ##        
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @992 '?' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x01, 0x80, //        ##  
  0x07, 0x00, //      ###   
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1024 '@' (11 pixels wide)
  0x00, 0x00, //            
  0x0E, 0x00, //     ###    
  0x11, 0x00, //    #   #   
  0x21, 0x00, //   #    #   
  0x21, 0x00, //   #    #   
  0x27, 0x00, //   #  ###   
  0x29, 0x00, //   # #  #   
  0x29, 0x00, //   # #  #   
  0x27, 0x00, //   #  ###   
  0x20, 0x00, //   #        
  0x11, 0x00, //    #   #   
  0x0E, 0x00, //     ###    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1056 'A' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x3F, 0x00, //   ######   
  0x0F, 0x00, //     ####   
  0x09, 0x00, //     #  #   
  0x19, 0x80, //    ##  ##  
  0x19, 0x80, //    ##  ##  
  0x1F, 0x80, //    ######  
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x79, 0xE0, //  ####  ####
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1088 'B' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x00, //  #######   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x00, //   ######   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x7F, 0x00, //  #######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1120 'C' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x40, //    ##### # 
  0x30, 0xC0, //   ##    ## 
  0x60, 0x40, //  ##      # 
  0x60, 0x00, //  ##        
  0x60, 0x00, //  ##        
  0x60, 0x00, //  ##        
  0x60, 0x40, //  ##      # 
  0x30, 0x80, //   ##    #  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1152 'D' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x00, //  #######   
  0x31, 0x80, //   ##   ##  
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x31, 0x80, //   ##   ##  
  0x7F, 0x00, //  #######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1184 'E' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x80, //  ########  
  0x30, 0x80, //   ##    #  
  0x30, 0x80, //   ##    #  
  0x32, 0x00, //   ##  #    
  0x3E, 0x00, //   #####    
  0x32, 0x00, //   ##  #    
  0x30, 0x80, //   ##    #  
  0x30, 0x80, //   ##    #  
  0x7F, 0x80, //  ########  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1216 'F' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0xC0, //  ######### 
  0x30, 0x40, //   ##     # 
  0x30, 0x40, //   ##     # 
  0x32, 0x00, //   ##  #    
  0x3E, 0x00, //   #####    
  0x32, 0x00, //   ##  #    
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x7C, 0x00, //  #####     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1248 'G' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1E, 0x80, //    #### #  
  0x31, 0x80, //   ##   ##  
  0x60, 0x80, //  ##     #  
  0x60, 0x00, //  ##        
  0x60, 0x00, //  ##        
  0x67, 0xC0, //  ##  ##### 
  0x61, 0x80, //  ##    ##  
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1280 'H' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x80, //   #######  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x7B, 0xC0, //  #### #### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1312 'I' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x3F, 0xC0, //   ######## 
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x3F, 0xC0, //   ######## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1344 'J' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0xC0, //    ####### 
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x63, 0x00, //  ##   ##   
  0x63, 0x00, //  ##   ##   
  0x63, 0x00, //  ##   ##   
  0x3E, 0x00, //   #####    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1376 'K' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x33, 0x00, //   ##  ##   
  0x36, 0x00, //   ## ##    
  0x3C, 0x00, //   ####     
  0x3E, 0x00, //   #####    
  0x33, 0x00, //   ##  ##   
  0x31, 0x80, //   ##   ##  
  0x79, 0xC0, //  ####  ### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1408 'L' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7E, 0x00, //  ######    
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x40, //    ##    # 
  0x18, 0x40, //    ##    # 
  0x18, 0x40, //    ##    # 
  0x7F, 0xC0, //  ######### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1440 'M' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0xE0, 0xE0, // ###     ###
  0x60, 0xC0, //  ##     ## 
  0x71, 0xC0, //  ###   ### 
  0x7B, 0xC0, //  #### #### 
  0x6A, 0xC0, //  ## # # ## 
  0x6E, 0xC0, //  ## ### ## 
  0x64, 0xC0, //  ##  #  ## 
  0x60, 0xC0, //  ##     ## 
  0xFB, 0xE0, // ##### #####
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1472 'N' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x73, 0xC0, //  ###  #### 
  0x31, 0x80, //   ##   ##  
  0x39, 0x80, //   ###  ##  
  0x3D, 0x80, //   #### ##  
  0x35, 0x80, //   ## # ##  
  0x37, 0x80, //   ## ####  
  0x33, 0x80, //   ##  ###  
  0x31, 0x80, //   ##   ##  
  0x79, 0x80, //  ####  ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1504 'O' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1536 'P' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x00, //  #######   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x00, //   ######   
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x7E, 0x00, //  ######    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1568 'Q' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x0C, 0xC0, //     ##  ## 
  0x1F, 0x80, //    ######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1600 'R' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x00, //  #######   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3E, 0x00, //   #####    
  0x33, 0x00, //   ##  ##   
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x7C, 0xE0, //  #####  ###
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1632 'S' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x80, //    ######  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x38, 0x00, //   ###      
  0x1F, 0x00, //    #####   
  0x03, 0x80, //       ###  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x00, //   ######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1664 'T' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x80, //  ########  
  0x4C, 0x80, //  #  ##  #  
  0x4C, 0x80, //  #  ##  #  
  0x4C, 0x80, //  #  ##  #  
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x3F, 0x00, //   ######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1696 'U' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1728 'V' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x0A, 0x00, //     # #    
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1760 'W' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0xFB, 0xE0, // ##### #####
  0x60, 0xC0, //  ##     ## 
  0x64, 0xC0, //  ##  #  ## 
  0x6E, 0xC0, //  ## ### ## 
  0x6E, 0xC0, //  ## ### ## 
  0x2A, 0x80, //   # # # #  
  0x3B, 0x80, //   ### ###  
  0x3B, 0x80, //   ### ###  
  0x31, 0x80, //   ##   ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1792 'X' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x1B, 0x00, //    ## ##   
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x1B, 0x00, //    ## ##   
  0x31, 0x80, //   ##   ##  
  0x7B, 0xC0, //  #### #### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1824 'Y' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x79, 0xE0, //  ####  ####
  0x30, 0xC0, //   ##    ## 
  0x19, 0x80, //    ##  ##  
  0x0F, 0x00, //     ####   
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x1F, 0x80, //    ######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1856 'Z' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x3F, 0x80, //   #######  
  0x21, 0x80, //   #    ##  
  0x23, 0x00, //   #   ##   
  0x06, 0x00, //      ##    
  0x04, 0x00, //      #     
  0x0C, 0x00, //     ##     
  0x18, 0x80, //    ##   #  
  0x30, 0x80, //   ##    #  
  0x3F, 0x80, //   #######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1888 '[' (11 pixels wide)
  0x00, 0x00, //            
  0x07, 0x80, //      ####  
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x07, 0x80, //      ####  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1920 '\' (11 pixels wide)
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x06, 0x00, //      ##    
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x00, 0xC0, //         ## 
  0x00, 0xC0, //         ## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1952 ']' (11 pixels wide)
  0x00, 0x00, //            
  0x1E, 0x00, //    ####    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x1E, 0x00, //    ####    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @1984 '^' (11 pixels wide)
  0x04, 0x00, //      #     
  0x0A, 0x00, //     # #    
  0x0A, 0x00, //     # #    
  0x11, 0x00, //    #   #   
  0x20, 0x80, //   #     #  
  0x20, 0x80, //   #     #  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2016 '_' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0xFF, 0xE0, // ###########

  // @2048 '`' (11 pixels wide)
  0x08, 0x00, //     #      
  0x04, 0x00, //      #     
  0x02, 0x00, //       #    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2080 'a' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x1F, 0x80, //    ######  
  0x31, 0x80, //   ##   ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0xC0, //    ### ### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2112 'b' (11 pixels wide)
  0x00, 0x00, //            
  0x70, 0x00, //  ###       
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x37, 0x00, //   ## ###   
  0x39, 0x80, //   ###  ##  
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x39, 0x80, //   ###  ##  
  0x77, 0x00, //  ### ###   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2144 'c' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1E, 0x80, //    #### #  
  0x31, 0x80, //   ##   ##  
  0x60, 0x80, //  ##     #  
  0x60, 0x00, //  ##        
  0x60, 0x80, //  ##     #  
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2176 'd' (11 pixels wide)
  0x00, 0x00, //            
  0x03, 0x80, //       ###  
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x1D, 0x80, //    ### ##  
  0x33, 0x80, //   ##  ###  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0xC0, //    ### ### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2208 'e' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x60, 0xC0, //  ##     ## 
  0x7F, 0xC0, //  ######### 
  0x60, 0x00, //  ##        
  0x30, 0xC0, //   ##    ## 
  0x1F, 0x80, //    ######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2240 'f' (11 pixels wide)
  0x00, 0x00, //            
  0x07, 0xE0, //      ######
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x3F, 0x80, //   #######  
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x3F, 0x80, //   #######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2272 'g' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1D, 0xC0, //    ### ### 
  0x33, 0x80, //   ##  ###  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0x80, //    ### ##  
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2304 'h' (11 pixels wide)
  0x00, 0x00, //            
  0x70, 0x00, //  ###       
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x37, 0x00, //   ## ###   
  0x39, 0x80, //   ###  ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x7B, 0xC0, //  #### #### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2336 'i' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x00, 0x00, //            
  0x1E, 0x00, //    ####    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x3F, 0xC0, //   ######## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2368 'j' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x00, 0x00, //            
  0x3F, 0x00, //   ######   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x03, 0x00, //       ##   
  0x3E, 0x00, //   #####    
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2400 'k' (11 pixels wide)
  0x00, 0x00, //            
  0x70, 0x00, //  ###       
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x37, 0x80, //   ## ####  
  0x36, 0x00, //   ## ##    
  0x3C, 0x00, //   ####     
  0x3C, 0x00, //   ####     
  0x36, 0x00, //   ## ##    
  0x33, 0x00, //   ##  ##   
  0x77, 0xC0, //  ### ##### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2432 'l' (11 pixels wide)
  0x00, 0x00, //            
  0x1E, 0x00, //    ####    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x3F, 0xC0, //   ######## 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2464 'm' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7F, 0x80, //  ########  
  0x36, 0xC0, //   ## ## ## 
  0x36, 0xC0, //   ## ## ## 
  0x36, 0xC0, //   ## ## ## 
  0x36, 0xC0, //   ## ## ## 
  0x36, 0xC0, //   ## ## ## 
  0x76, 0xE0, //  ### ## ###
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2496 'n' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x77, 0x00, //  ### ###   
  0x39, 0x80, //   ###  ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x7B, 0xC0, //  #### #### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2528 'o' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x00, //    #####   
  0x31, 0x80, //   ##   ##  
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x60, 0xC0, //  ##     ## 
  0x31, 0x80, //   ##   ##  
  0x1F, 0x00, //    #####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2560 'p' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x77, 0x00, //  ### ###   
  0x39, 0x80, //   ###  ##  
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x30, 0xC0, //   ##    ## 
  0x39, 0x80, //   ###  ##  
  0x37, 0x00, //   ## ###   
  0x30, 0x00, //   ##       
  0x30, 0x00, //   ##       
  0x7C, 0x00, //  #####     
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2592 'q' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1D, 0xC0, //    ### ### 
  0x33, 0x80, //   ##  ###  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x61, 0x80, //  ##    ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0x80, //    ### ##  
  0x01, 0x80, //        ##  
  0x01, 0x80, //        ##  
  0x07, 0xC0, //      ##### 
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2624 'r' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0x80, //  #### ###  
  0x1C, 0xC0, //    ###  ## 
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x7F, 0x00, //  #######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2656 's' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x1F, 0x80, //    ######  
  0x31, 0x80, //   ##   ##  
  0x3C, 0x00, //   ####     
  0x1F, 0x00, //    #####   
  0x03, 0x80, //       ###  
  0x31, 0x80, //   ##   ##  
  0x3F, 0x00, //   ######   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2688 't' (11 pixels wide)
  0x00, 0x00, //            
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x7F, 0x00, //  #######   
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x00, //    ##      
  0x18, 0x80, //    ##   #  
  0x0F, 0x00, //     ####   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2720 'u' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x73, 0x80, //  ###  ###  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x33, 0x80, //   ##  ###  
  0x1D, 0xC0, //    ### ### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2752 'v' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x31, 0x80, //   ##   ##  
  0x31, 0x80, //   ##   ##  
  0x1B, 0x00, //    ## ##   
  0x1B, 0x00, //    ## ##   
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2784 'w' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0xF1, 0xE0, // ####   ####
  0x60, 0xC0, //  ##     ## 
  0x64, 0xC0, //  ##  #  ## 
  0x6E, 0xC0, //  ## ### ## 
  0x3B, 0x80, //   ### ###  
  0x3B, 0x80, //   ### ###  
  0x31, 0x80, //   ##   ##  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2816 'x' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x7B, 0xC0, //  #### #### 
  0x1B, 0x00, //    ## ##   
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x0E, 0x00, //     ###    
  0x1B, 0x00, //    ## ##   
  0x7B, 0xC0, //  #### #### 
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2848 'y' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x79, 0xE0, //  ####  ####
  0x30, 0xC0, //   ##    ## 
  0x19, 0x80, //    ##  ##  
  0x19, 0x80, //    ##  ##  
  0x0B, 0x00, //     # ##   
  0x0F, 0x00, //     ####   
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x3E, 0x00, //   #####    
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2880 'z' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x3F, 0x80, //   #######  
  0x21, 0x80, //   #    ##  
  0x03, 0x00, //       ##   
  0x0E, 0x00, //     ###    
  0x18, 0x00, //    ##      
  0x30, 0x80, //   ##    #  
  0x3F, 0x80, //   #######  
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2912 '{' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x18, 0x00, //    ##      
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x0C, 0x00, //     ##     
  0x06, 0x00, //      ##    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2944 '|' (11 pixels wide)
  0x00, 0x00, //            
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @2976 '}' (11 pixels wide)
  0x00, 0x00, //            
  0x0C, 0x00, //     ##     
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x03, 0x00, //       ##   
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x06, 0x00, //      ##    
  0x0C, 0x00, //     ##     
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            

  // @3008 '~' (11 pixels wide)
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x18, 0x00, //    ##      
  0x24, 0x80, //   #  #  #  
  0x03, 0x00, //       ##   
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
  0x00, 0x00, //            
};

sFONT Font16 = 
{
  Font16_Table,
  11,		// Width
  16,		// Height
  0x20,		// First ' '
  0x7E		// Last '~'

};

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


================================================
FILE: font20.c
================================================
/**
  ******************************************************************************
  * @file    font20.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    18-February-2014
  * @brief   This file provides text font20 for STM32xx-EVAL's LCD driver. 
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "fonts.h"

// Character bitmaps for Courier New 15pt
const uint8_t Font20_Table[] =
{
  // @0 ' ' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @40 '!' (14 pixels wide)
  0x00, 0x00, //               
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x02, 0x00, //       #       
  0x02, 0x00, //       #       
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @80 '"' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1C, 0xE0, //    ###  ###   
  0x1C, 0xE0, //    ###  ###   
  0x1C, 0xE0, //    ###  ###   
  0x08, 0x40, //     #    #    
  0x08, 0x40, //     #    #    
  0x08, 0x40, //     #    #    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @120 '#' (14 pixels wide)
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @160 '$' (14 pixels wide)
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x07, 0xE0, //      ######   
  0x0F, 0xE0, //     #######   
  0x18, 0x60, //    ##    ##   
  0x18, 0x00, //    ##         
  0x1F, 0x00, //    #####      
  0x0F, 0xC0, //     ######    
  0x00, 0xE0, //         ###   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x1F, 0xC0, //    #######    
  0x1F, 0x80, //    ######     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @200 '%' (14 pixels wide)
  0x00, 0x00, //               
  0x1C, 0x00, //    ###        
  0x22, 0x00, //   #   #       
  0x22, 0x00, //   #   #       
  0x22, 0x00, //   #   #       
  0x1C, 0x60, //    ###   ##   
  0x01, 0xE0, //        ####   
  0x0F, 0x80, //     #####     
  0x3C, 0x00, //   ####        
  0x31, 0xC0, //   ##   ###    
  0x02, 0x20, //       #   #   
  0x02, 0x20, //       #   #   
  0x02, 0x20, //       #   #   
  0x01, 0xC0, //        ###    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @240 '&' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0xE0, //       #####   
  0x0F, 0xE0, //     #######   
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x06, 0x00, //      ##       
  0x0F, 0x30, //     ####  ##  
  0x1F, 0xF0, //    #########  
  0x19, 0xE0, //    ##  ####   
  0x18, 0xC0, //    ##   ##    
  0x1F, 0xF0, //    #########  
  0x07, 0xB0, //      #### ##  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @280 ''' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x01, 0x00, //        #      
  0x01, 0x00, //        #      
  0x01, 0x00, //        #      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @320 '(' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @360 ')' (14 pixels wide)
  0x00, 0x00, //               
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @400 '*' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x1B, 0x60, //    ## ## ##   
  0x1F, 0xE0, //    ########   
  0x07, 0x80, //      ####     
  0x07, 0x80, //      ####     
  0x0F, 0xC0, //     ######    
  0x0C, 0xC0, //     ##  ##    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @440 '+' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @480 ',' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x04, 0x00, //      #        
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @520 '-' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xE0, //   #########   
  0x3F, 0xE0, //   #########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @560 '.' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @600 '/' (14 pixels wide)
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @640 '0' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x80, //     #####     
  0x1F, 0xC0, //    #######    
  0x18, 0xC0, //    ##   ##    
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x18, 0xC0, //    ##   ##    
  0x1F, 0xC0, //    #######    
  0x0F, 0x80, //     #####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @680 '1' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x1F, 0x00, //    #####      
  0x1F, 0x00, //    #####      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @720 '2' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x80, //     #####     
  0x1F, 0xC0, //    #######    
  0x38, 0xE0, //   ###   ###   
  0x30, 0x60, //   ##     ##   
  0x00, 0x60, //          ##   
  0x00, 0xC0, //         ##    
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x0C, 0x00, //     ##        
  0x18, 0x00, //    ##         
  0x3F, 0xE0, //   #########   
  0x3F, 0xE0, //   #########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @760 '3' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x80, //     #####     
  0x3F, 0xC0, //   ########    
  0x30, 0xE0, //   ##    ###   
  0x00, 0x60, //          ##   
  0x00, 0xE0, //         ###   
  0x07, 0xC0, //      #####    
  0x07, 0xC0, //      #####    
  0x00, 0xE0, //         ###   
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x60, 0xE0, //  ##     ###   
  0x7F, 0xC0, //  #########    
  0x3F, 0x80, //   #######     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @800 '4' (14 pixels wide)
  0x00, 0x00, //               
  0x01, 0xC0, //        ###    
  0x03, 0xC0, //       ####    
  0x03, 0xC0, //       ####    
  0x06, 0xC0, //      ## ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0xC0, //     ##  ##    
  0x18, 0xC0, //    ##   ##    
  0x30, 0xC0, //   ##    ##    
  0x3F, 0xE0, //   #########   
  0x3F, 0xE0, //   #########   
  0x00, 0xC0, //         ##    
  0x03, 0xE0, //       #####   
  0x03, 0xE0, //       #####   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @840 '5' (14 pixels wide)
  0x00, 0x00, //               
  0x1F, 0xC0, //    #######    
  0x1F, 0xC0, //    #######    
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x1F, 0x80, //    ######     
  0x1F, 0xC0, //    #######    
  0x18, 0xE0, //    ##   ###   
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x30, 0xE0, //   ##    ###   
  0x3F, 0xC0, //   ########    
  0x1F, 0x80, //    ######     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @880 '6' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0xE0, //       #####   
  0x0F, 0xE0, //     #######   
  0x1E, 0x00, //    ####       
  0x18, 0x00, //    ##         
  0x38, 0x00, //   ###         
  0x37, 0x80, //   ## ####     
  0x3F, 0xC0, //   ########    
  0x38, 0xE0, //   ###   ###   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x18, 0xE0, //    ##   ###   
  0x1F, 0xC0, //    #######    
  0x07, 0x80, //      ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @920 '7' (14 pixels wide)
  0x00, 0x00, //               
  0x3F, 0xE0, //   #########   
  0x3F, 0xE0, //   #########   
  0x30, 0x60, //   ##     ##   
  0x00, 0x60, //          ##   
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @960 '8' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x80, //     #####     
  0x1F, 0xC0, //    #######    
  0x38, 0xE0, //   ###   ###   
  0x30, 0x60, //   ##     ##   
  0x38, 0xE0, //   ###   ###   
  0x1F, 0xC0, //    #######    
  0x1F, 0xC0, //    #######    
  0x38, 0xE0, //   ###   ###   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x38, 0xE0, //   ###   ###   
  0x1F, 0xC0, //    #######    
  0x0F, 0x80, //     #####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1000 '9' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x00, //     ####      
  0x1F, 0xC0, //    #######    
  0x38, 0xC0, //   ###   ##    
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x38, 0xE0, //   ###   ###   
  0x1F, 0xE0, //    ########   
  0x0F, 0x60, //     #### ##   
  0x00, 0xE0, //         ###   
  0x00, 0xC0, //         ##    
  0x03, 0xC0, //       ####    
  0x3F, 0x80, //   #######     
  0x3E, 0x00, //   #####       
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1040 ':' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x03, 0x80, //       ###     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1080 ';' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x01, 0xC0, //        ###    
  0x01, 0xC0, //        ###    
  0x01, 0xC0, //        ###    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x04, 0x00, //      #        
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1120 '<' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x30, //           ##  
  0x00, 0xF0, //         ####  
  0x03, 0xC0, //       ####    
  0x07, 0x00, //      ###      
  0x1C, 0x00, //    ###        
  0x78, 0x00, //  ####         
  0x1C, 0x00, //    ###        
  0x07, 0x00, //      ###      
  0x03, 0xC0, //       ####    
  0x00, 0xF0, //         ####  
  0x00, 0x30, //           ##  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1160 '=' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x7F, 0xF0, //  ###########  
  0x7F, 0xF0, //  ###########  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x7F, 0xF0, //  ###########  
  0x7F, 0xF0, //  ###########  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1200 '>' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x30, 0x00, //   ##          
  0x3C, 0x00, //   ####        
  0x0F, 0x00, //     ####      
  0x03, 0x80, //       ###     
  0x00, 0xE0, //         ###   
  0x00, 0x78, //          #### 
  0x00, 0xE0, //         ###   
  0x03, 0x80, //       ###     
  0x0F, 0x00, //     ####      
  0x3C, 0x00, //   ####        
  0x30, 0x00, //   ##          
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1240 '?' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x0F, 0x80, //     #####     
  0x1F, 0xC0, //    #######    
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x00, 0x60, //          ##   
  0x01, 0xC0, //        ###    
  0x03, 0x80, //       ###     
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1280 '@' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x80, //       ###     
  0x0C, 0x80, //     ##  #     
  0x08, 0x40, //     #    #    
  0x10, 0x40, //    #     #    
  0x10, 0x40, //    #     #    
  0x11, 0xC0, //    #   ###    
  0x12, 0x40, //    #  #  #    
  0x12, 0x40, //    #  #  #    
  0x12, 0x40, //    #  #  #    
  0x11, 0xC0, //    #   ###    
  0x10, 0x00, //    #          
  0x08, 0x00, //     #         
  0x08, 0x40, //     #    #    
  0x07, 0x80, //      ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1320 'A' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0x80, //    ######     
  0x1F, 0x80, //    ######     
  0x03, 0x80, //       ###     
  0x06, 0xC0, //      ## ##    
  0x06, 0xC0, //      ## ##    
  0x0C, 0xC0, //     ##  ##    
  0x0C, 0x60, //     ##   ##   
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x30, 0x30, //   ##      ##  
  0x78, 0x78, //  ####    #### 
  0x78, 0x78, //  ####    #### 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1360 'B' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0x80, //   #######     
  0x3F, 0xC0, //   ########    
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0xE0, //    ##   ###   
  0x1F, 0xC0, //    #######    
  0x1F, 0xE0, //    ########   
  0x18, 0x70, //    ##    ###  
  0x18, 0x30, //    ##     ##  
  0x18, 0x30, //    ##     ##  
  0x3F, 0xF0, //   ##########  
  0x3F, 0xE0, //   #########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1400 'C' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xB0, //      #### ##  
  0x0F, 0xF0, //     ########  
  0x1C, 0x70, //    ###   ###  
  0x38, 0x30, //   ###     ##  
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x38, 0x30, //   ###     ##  
  0x1C, 0x70, //    ###   ###  
  0x0F, 0xE0, //     #######   
  0x07, 0xC0, //      #####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1440 'D' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x7F, 0x80, //  ########     
  0x7F, 0xC0, //  #########    
  0x30, 0xE0, //   ##    ###   
  0x30, 0x70, //   ##     ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x70, //   ##     ###  
  0x30, 0xE0, //   ##    ###   
  0x7F, 0xC0, //  #########    
  0x7F, 0x80, //  ########     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1480 'E' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x18, 0x30, //    ##     ##  
  0x18, 0x30, //    ##     ##  
  0x19, 0x80, //    ##  ##     
  0x1F, 0x80, //    ######     
  0x1F, 0x80, //    ######     
  0x19, 0x80, //    ##  ##     
  0x18, 0x30, //    ##     ##  
  0x18, 0x30, //    ##     ##  
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1520 'F' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x18, 0x30, //    ##     ##  
  0x18, 0x30, //    ##     ##  
  0x19, 0x80, //    ##  ##     
  0x1F, 0x80, //    ######     
  0x1F, 0x80, //    ######     
  0x19, 0x80, //    ##  ##     
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x3F, 0x00, //   ######      
  0x3F, 0x00, //   ######      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1560 'G' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xB0, //      #### ##  
  0x1F, 0xF0, //    #########  
  0x18, 0x70, //    ##    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x31, 0xF8, //   ##   ###### 
  0x31, 0xF8, //   ##   ###### 
  0x30, 0x30, //   ##      ##  
  0x18, 0x30, //    ##     ##  
  0x1F, 0xF0, //    #########  
  0x07, 0xC0, //      #####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1600 'H' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1640 'I' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1680 'J' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x03, 0xF8, //       ####### 
  0x03, 0xF8, //       ####### 
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x30, 0xE0, //   ##    ###   
  0x3F, 0xC0, //   ########    
  0x0F, 0x80, //     #####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1720 'K' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3E, 0xF8, //   ##### ##### 
  0x3E, 0xF8, //   ##### ##### 
  0x18, 0xE0, //    ##   ###   
  0x19, 0x80, //    ##  ##     
  0x1B, 0x00, //    ## ##      
  0x1F, 0x00, //    #####      
  0x1D, 0x80, //    ### ##     
  0x18, 0xC0, //    ##   ##    
  0x18, 0xC0, //    ##   ##    
  0x18, 0x60, //    ##    ##   
  0x3E, 0x78, //   #####  #### 
  0x3E, 0x38, //   #####   ### 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1760 'L' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0x00, //   ######      
  0x3F, 0x00, //   ######      
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x30, //     ##    ##  
  0x0C, 0x30, //     ##    ##  
  0x0C, 0x30, //     ##    ##  
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1800 'M' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0x78, //  ####    #### 
  0x78, 0x78, //  ####    #### 
  0x38, 0x70, //   ###    ###  
  0x3C, 0xF0, //   ####  ####  
  0x34, 0xB0, //   ## #  # ##  
  0x37, 0xB0, //   ## #### ##  
  0x37, 0xB0, //   ## #### ##  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x30, 0x30, //   ##      ##  
  0x7C, 0xF8, //  #####  ##### 
  0x7C, 0xF8, //  #####  ##### 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1840 'N' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x39, 0xF0, //   ###  #####  
  0x3D, 0xF0, //   #### #####  
  0x1C, 0x60, //    ###   ##   
  0x1E, 0x60, //    ####  ##   
  0x1E, 0x60, //    ####  ##   
  0x1B, 0x60, //    ## ## ##   
  0x1B, 0x60, //    ## ## ##   
  0x19, 0xE0, //    ##  ####   
  0x19, 0xE0, //    ##  ####   
  0x18, 0xE0, //    ##   ###   
  0x3E, 0xE0, //   ##### ###   
  0x3E, 0x60, //   #####  ##   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1880 'O' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x80, //      ####     
  0x0F, 0xC0, //     ######    
  0x1C, 0xE0, //    ###  ###   
  0x38, 0x70, //   ###    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x38, 0x70, //   ###    ###  
  0x1C, 0xE0, //    ###  ###   
  0x0F, 0xC0, //     ######    
  0x07, 0x80, //      ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1920 'P' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xC0, //   ########    
  0x3F, 0xE0, //   #########   
  0x18, 0x70, //    ##    ###  
  0x18, 0x30, //    ##     ##  
  0x18, 0x30, //    ##     ##  
  0x18, 0x70, //    ##    ###  
  0x1F, 0xE0, //    ########   
  0x1F, 0xC0, //    #######    
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x3F, 0x00, //   ######      
  0x3F, 0x00, //   ######      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @1960 'Q' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x80, //      ####     
  0x0F, 0xC0, //     ######    
  0x1C, 0xE0, //    ###  ###   
  0x38, 0x70, //   ###    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x38, 0x70, //   ###    ###  
  0x1C, 0xE0, //    ###  ###   
  0x0F, 0xC0, //     ######    
  0x07, 0x80, //      ####     
  0x07, 0xB0, //      #### ##  
  0x0F, 0xF0, //     ########  
  0x0C, 0xE0, //     ##  ###   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2000 'R' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xC0, //   ########    
  0x3F, 0xE0, //   #########   
  0x18, 0x70, //    ##    ###  
  0x18, 0x30, //    ##     ##  
  0x18, 0x70, //    ##    ###  
  0x1F, 0xE0, //    ########   
  0x1F, 0xC0, //    #######    
  0x18, 0xE0, //    ##   ###   
  0x18, 0x60, //    ##    ##   
  0x18, 0x70, //    ##    ###  
  0x3E, 0x38, //   #####   ### 
  0x3E, 0x18, //   #####    ## 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2040 'S' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x0F, 0xB0, //     ##### ##  
  0x1F, 0xF0, //    #########  
  0x38, 0x70, //   ###    ###  
  0x30, 0x30, //   ##      ##  
  0x38, 0x00, //   ###         
  0x1F, 0x80, //    ######     
  0x07, 0xE0, //      ######   
  0x00, 0x70, //          ###  
  0x30, 0x30, //   ##      ##  
  0x38, 0x70, //   ###    ###  
  0x3F, 0xE0, //   #########   
  0x37, 0xC0, //   ## #####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2080 'T' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x0F, 0xC0, //     ######    
  0x0F, 0xC0, //     ######    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2120 'U' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x1C, 0xE0, //    ###  ###   
  0x0F, 0xC0, //     ######    
  0x07, 0x80, //      ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2160 'V' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x30, 0x60, //   ##     ##   
  0x30, 0x60, //   ##     ##   
  0x18, 0xC0, //    ##   ##    
  0x18, 0xC0, //    ##   ##    
  0x0D, 0x80, //     ## ##     
  0x0D, 0x80, //     ## ##     
  0x0D, 0x80, //     ## ##     
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2200 'W' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x7C, 0x7C, //  #####   #####
  0x7C, 0x7C, //  #####   #####
  0x30, 0x18, //   ##       ## 
  0x33, 0x98, //   ##  ###  ## 
  0x33, 0x98, //   ##  ###  ## 
  0x33, 0x98, //   ##  ###  ## 
  0x36, 0xD8, //   ## ## ## ## 
  0x16, 0xD0, //    # ## ## #  
  0x1C, 0x70, //    ###   ###  
  0x1C, 0x70, //    ###   ###  
  0x1C, 0x70, //    ###   ###  
  0x18, 0x30, //    ##     ##  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2240 'X' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x30, 0x60, //   ##     ##   
  0x18, 0xC0, //    ##   ##    
  0x0D, 0x80, //     ## ##     
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x0D, 0x80, //     ## ##     
  0x18, 0xC0, //    ##   ##    
  0x30, 0x60, //   ##     ##   
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2280 'Y' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x18, 0x60, //    ##    ##   
  0x0C, 0xC0, //     ##  ##    
  0x07, 0x80, //      ####     
  0x07, 0x80, //      ####     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x0F, 0xC0, //     ######    
  0x0F, 0xC0, //     ######    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2320 'Z' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x18, 0x60, //    ##    ##   
  0x18, 0xC0, //    ##   ##    
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x0C, 0x60, //     ##   ##   
  0x18, 0x60, //    ##    ##   
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2360 '[' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0xC0, //       ####    
  0x03, 0xC0, //       ####    
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0xC0, //       ####    
  0x03, 0xC0, //       ####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2400 '\' (14 pixels wide)
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x01, 0x80, //        ##     
  0x01, 0x80, //        ##     
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0x60, //          ##   
  0x00, 0x60, //          ##   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2440 ']' (14 pixels wide)
  0x00, 0x00, //               
  0x0F, 0x00, //     ####      
  0x0F, 0x00, //     ####      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x0F, 0x00, //     ####      
  0x0F, 0x00, //     ####      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2480 '^' (14 pixels wide)
  0x00, 0x00, //               
  0x02, 0x00, //       #       
  0x07, 0x00, //      ###      
  0x0D, 0x80, //     ## ##     
  0x18, 0xC0, //    ##   ##    
  0x30, 0x60, //   ##     ##   
  0x20, 0x20, //   #       #   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2520 '_' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0xFF, 0xFC, // ##############
  0xFF, 0xFC, // ##############

  // @2560 '`' (14 pixels wide)
  0x00, 0x00, //               
  0x04, 0x00, //      #        
  0x03, 0x00, //       ##      
  0x00, 0x80, //         #     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2600 'a' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x0F, 0xC0, //     ######    
  0x1F, 0xE0, //    ########   
  0x00, 0x60, //          ##   
  0x0F, 0xE0, //     #######   
  0x1F, 0xE0, //    ########   
  0x38, 0x60, //   ###    ##   
  0x30, 0xE0, //   ##    ###   
  0x3F, 0xF0, //   ##########  
  0x1F, 0x70, //    ##### ###  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2640 'b' (14 pixels wide)
  0x00, 0x00, //               
  0x70, 0x00, //  ###          
  0x70, 0x00, //  ###          
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x37, 0x80, //   ## ####     
  0x3F, 0xE0, //   #########   
  0x38, 0x60, //   ###    ##   
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x38, 0x60, //   ###    ##   
  0x7F, 0xE0, //  ##########   
  0x77, 0x80, //  ### ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2680 'c' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xB0, //      #### ##  
  0x1F, 0xF0, //    #########  
  0x18, 0x30, //    ##     ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x38, 0x30, //   ###     ##  
  0x1F, 0xF0, //    #########  
  0x0F, 0xC0, //     ######    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2720 'd' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x70, //          ###  
  0x00, 0x70, //          ###  
  0x00, 0x30, //           ##  
  0x00, 0x30, //           ##  
  0x07, 0xB0, //      #### ##  
  0x1F, 0xF0, //    #########  
  0x18, 0x70, //    ##    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x38, 0x70, //   ###    ###  
  0x1F, 0xF8, //    ########## 
  0x07, 0xB8, //      #### ### 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2760 'e' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x80, //      ####     
  0x1F, 0xE0, //    ########   
  0x18, 0x60, //    ##    ##   
  0x3F, 0xF0, //   ##########  
  0x3F, 0xF0, //   ##########  
  0x30, 0x00, //   ##          
  0x18, 0x30, //    ##     ##  
  0x1F, 0xF0, //    #########  
  0x07, 0xC0, //      #####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2800 'f' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0xF0, //       ######  
  0x07, 0xF0, //      #######  
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2840 'g' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xB8, //      #### ### 
  0x1F, 0xF8, //    ########## 
  0x18, 0x70, //    ##    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x18, 0x70, //    ##    ###  
  0x1F, 0xF0, //    #########  
  0x07, 0xB0, //      #### ##  
  0x00, 0x30, //           ##  
  0x00, 0x70, //          ###  
  0x0F, 0xE0, //     #######   
  0x0F, 0xC0, //     ######    
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2880 'h' (14 pixels wide)
  0x00, 0x00, //               
  0x38, 0x00, //   ###         
  0x38, 0x00, //   ###         
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x1B, 0xC0, //    ## ####    
  0x1F, 0xE0, //    ########   
  0x1C, 0x60, //    ###   ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2920 'i' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0x00, //    #####      
  0x1F, 0x00, //    #####      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @2960 'j' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0xC0, //    #######    
  0x1F, 0xC0, //    #######    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x00, 0xC0, //         ##    
  0x01, 0xC0, //        ###    
  0x3F, 0x80, //   #######     
  0x3F, 0x00, //   ######      
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3000 'k' (14 pixels wide)
  0x00, 0x00, //               
  0x38, 0x00, //   ###         
  0x38, 0x00, //   ###         
  0x18, 0x00, //    ##         
  0x18, 0x00, //    ##         
  0x1B, 0xE0, //    ## #####   
  0x1B, 0xE0, //    ## #####   
  0x1B, 0x00, //    ## ##      
  0x1E, 0x00, //    ####       
  0x1E, 0x00, //    ####       
  0x1B, 0x00, //    ## ##      
  0x19, 0x80, //    ##  ##     
  0x39, 0xF0, //   ###  #####  
  0x39, 0xF0, //   ###  #####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3040 'l' (14 pixels wide)
  0x00, 0x00, //               
  0x1F, 0x00, //    #####      
  0x1F, 0x00, //    #####      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3080 'm' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x7E, 0xE0, //  ###### ###   
  0x7F, 0xF0, //  ###########  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x33, 0x30, //   ##  ##  ##  
  0x7B, 0xB8, //  #### ### ### 
  0x7B, 0xB8, //  #### ### ### 
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3120 'n' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3B, 0xC0, //   ### ####    
  0x3F, 0xE0, //   #########   
  0x1C, 0x60, //    ###   ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3160 'o' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0x80, //      ####     
  0x1F, 0xE0, //    ########   
  0x18, 0x60, //    ##    ##   
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x18, 0x60, //    ##    ##   
  0x1F, 0xE0, //    ########   
  0x07, 0x80, //      ####     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3200 'p' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x77, 0x80, //  ### ####     
  0x7F, 0xE0, //  ##########   
  0x38, 0x60, //   ###    ##   
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x38, 0x60, //   ###    ##   
  0x3F, 0xE0, //   #########   
  0x37, 0x80, //   ## ####     
  0x30, 0x00, //   ##          
  0x30, 0x00, //   ##          
  0x7C, 0x00, //  #####        
  0x7C, 0x00, //  #####        
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3240 'q' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xB8, //      #### ### 
  0x1F, 0xF8, //    ########## 
  0x18, 0x70, //    ##    ###  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x30, 0x30, //   ##      ##  
  0x18, 0x70, //    ##    ###  
  0x1F, 0xF0, //    #########  
  0x07, 0xB0, //      #### ##  
  0x00, 0x30, //           ##  
  0x00, 0x30, //           ##  
  0x00, 0xF8, //         ##### 
  0x00, 0xF8, //         ##### 
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3280 'r' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3C, 0xE0, //   ####  ###   
  0x3D, 0xF0, //   #### #####  
  0x0F, 0x30, //     ####  ##  
  0x0E, 0x00, //     ###       
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x3F, 0xC0, //   ########    
  0x3F, 0xC0, //   ########    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3320 's' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x07, 0xE0, //      ######   
  0x1F, 0xE0, //    ########   
  0x18, 0x60, //    ##    ##   
  0x1E, 0x00, //    ####       
  0x0F, 0xC0, //     ######    
  0x01, 0xE0, //        ####   
  0x18, 0x60, //    ##    ##   
  0x1F, 0xE0, //    ########   
  0x1F, 0x80, //    ######     
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3360 't' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x3F, 0xE0, //   #########   
  0x3F, 0xE0, //   #########   
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x00, //     ##        
  0x0C, 0x30, //     ##    ##  
  0x0F, 0xF0, //     ########  
  0x07, 0xC0, //      #####    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3400 'u' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x38, 0xE0, //   ###   ###   
  0x38, 0xE0, //   ###   ###   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0x60, //    ##    ##   
  0x18, 0xE0, //    ##   ###   
  0x1F, 0xF0, //    #########  
  0x0F, 0x70, //     #### ###  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3440 'v' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x30, 0x60, //   ##     ##   
  0x18, 0xC0, //    ##   ##    
  0x18, 0xC0, //    ##   ##    
  0x0D, 0x80, //     ## ##     
  0x0D, 0x80, //     ## ##     
  0x07, 0x00, //      ###      
  0x07, 0x00, //      ###      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3480 'w' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x32, 0x60, //   ##  #  ##   
  0x32, 0x60, //   ##  #  ##   
  0x37, 0xE0, //   ## ######   
  0x1D, 0xC0, //    ### ###    
  0x1D, 0xC0, //    ### ###    
  0x18, 0xC0, //    ##   ##    
  0x18, 0xC0, //    ##   ##    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3520 'x' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x0C, 0xC0, //     ##  ##    
  0x07, 0x80, //      ####     
  0x03, 0x00, //       ##      
  0x07, 0x80, //      ####     
  0x0C, 0xC0, //     ##  ##    
  0x3C, 0xF0, //   ####  ####  
  0x3C, 0xF0, //   ####  ####  
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3560 'y' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x78, 0xF0, //  ####   ####  
  0x78, 0xF0, //  ####   ####  
  0x30, 0x60, //   ##     ##   
  0x18, 0xC0, //    ##   ##    
  0x18, 0xC0, //    ##   ##    
  0x0D, 0x80, //     ## ##     
  0x0F, 0x80, //     #####     
  0x07, 0x00, //      ###      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x0C, 0x00, //     ##        
  0x7F, 0x00, //  #######      
  0x7F, 0x00, //  #######      
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3600 'z' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x18, 0xC0, //    ##   ##    
  0x01, 0x80, //        ##     
  0x03, 0x00, //       ##      
  0x06, 0x00, //      ##       
  0x0C, 0x60, //     ##   ##   
  0x1F, 0xE0, //    ########   
  0x1F, 0xE0, //    ########   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3640 '{' (14 pixels wide)
  0x00, 0x00, //               
  0x01, 0xC0, //        ###    
  0x03, 0xC0, //       ####    
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x07, 0x00, //      ###      
  0x0E, 0x00, //     ###       
  0x07, 0x00, //      ###      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0xC0, //       ####    
  0x01, 0xC0, //        ###    
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3680 '|' (14 pixels wide)
  0x00, 0x00, //               
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x03, 0x00, //       ##      
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3720 '}' (14 pixels wide)
  0x00, 0x00, //               
  0x1C, 0x00, //    ###        
  0x1E, 0x00, //    ####       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x07, 0x00, //      ###      
  0x03, 0x80, //       ###     
  0x07, 0x00, //      ###      
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x06, 0x00, //      ##       
  0x1E, 0x00, //    ####       
  0x1C, 0x00, //    ###        
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               

  // @3760 '~' (14 pixels wide)
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x0E, 0x00, //     ###       
  0x3F, 0x30, //   ######  ##  
  0x33, 0xF0, //   ##  ######  
  0x01, 0xE0, //        ####   
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
  0x00, 0x00, //               
};


sFONT Font20 = 
{
  Font20_Table,
  14,		// Width
  20,		// Height
  0x20,		// First ' '
  0x7E		// Last '`'
};

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


================================================
FILE: font24.c
================================================
/**
  ******************************************************************************
  * @file    font24.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    18-February-2014
  * @brief   This file provides text font24 for STM32xx-EVAL's LCD driver. 
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "fonts.h"

const uint8_t Font24_Table [] =
{
  // @0 ' ' (17 pixels wide)
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
  0x00, 0x00, 0x00, //                  
 
Download .txt
gitextract_jg7cwinb/

├── .github/
│   └── workflows/
│       └── cmake.yml
├── CMakeLists.txt
├── README.md
├── dsp.c
├── dsp.h
├── dsp_fft.c
├── dsp_tim.c
├── fix_fft.c
├── fix_fft.h
├── font16.c
├── font20.c
├── font24.c
├── font7spp.c
├── font8.c
├── fontAR.c
├── fontGR.c
├── fontSYM16.c
├── fontSYM32.c
├── fonts.h
├── fontub.c
├── fontubb.c
├── hmi.c
├── hmi.h
├── lcd.c
├── lcd.h
├── monitor.c
├── monitor.h
├── relay.c
├── relay.h
├── si5351.c
├── si5351.h
├── uSDR.c
└── uSDR.h
Download .txt
SYMBOL INDEX (66 symbols across 10 files)

FILE: dsp.c
  function dsp_setmode (line 60) | void dsp_setmode(int mode)
  function get_sval (line 94) | int get_sval(void)
  function dsp_setagc (line 132) | void dsp_setagc(int agc)
  function dsp_setvox (line 162) | void dsp_setvox(int vox)
  function mag (line 196) | inline uint16_t mag(int16_t i, int16_t q)
  function dsp_init (line 579) | void dsp_init()

FILE: fix_fft.c
  function q_add (line 321) | int16_t q_add(int16_t a, int16_t b)
  function q_sub (line 336) | int16_t q_sub(int16_t a, int16_t b)
  function q_mul (line 342) | int16_t q_mul(int16_t a, int16_t b)
  function q_div (line 359) | int16_t q_div(int16_t a, int16_t b)

FILE: fonts.h
  type sFONT (line 46) | typedef struct _tFont

FILE: hmi.c
  type fsm_t (line 139) | typedef struct
  function hmi_nop (line 155) | void hmi_nop(int event){}
  function hmi_tun (line 166) | void hmi_tun(int evt)
  function hmi_mod (line 203) | void hmi_mod(int evt)
  function hmi_agc (line 231) | void hmi_agc(int evt)
  function hmi_pre (line 259) | void hmi_pre(int evt)
  function hmi_vox (line 287) | void  hmi_vox(int evt)
  function hmi_callback (line 326) | void hmi_callback(uint gpio, uint32_t events)
  function hmi_layout (line 375) | void hmi_layout()
  function hmi_topline (line 398) | void hmi_topline()
  function hmi_frequency (line 433) | void hmi_frequency(double freq, int dig)
  function hmi_menu (line 460) | void hmi_menu()
  function hmi_evaluate (line 512) | void hmi_evaluate(void)
  function hmi_init (line 558) | void hmi_init(void)

FILE: lcd.c
  function lcd_reset (line 121) | void lcd_reset()
  function lcd_window (line 134) | int lcd_window(uint16_t c, uint16_t p, uint16_t w, uint16_t  h)
  function lcd_clear (line 168) | int lcd_clear(uint16_t c, uint16_t p, uint16_t w, uint16_t h, uint16_t c...
  function lcd_putxy (line 191) | int lcd_putxy(uint16_t x, uint16_t y, char c, sFONT* f, uint16_t fgc, ui...
  function lcd_writexy (line 253) | int lcd_writexy(uint16_t x, uint16_t y, char *s, sFONT* f, uint16_t fgc,...
  function lcd_init (line 275) | void lcd_init(void)
  function lcd_test (line 421) | void lcd_test(void)

FILE: monitor.c
  type shell_t (line 42) | typedef struct
  function mon_init (line 55) | void mon_init()
  function mon_flash (line 77) | void mon_flash(void)
  function mon_si (line 86) | void mon_si(void)
  function mon_vfo (line 107) | void mon_vfo(void)
  function mon_lt (line 127) | void mon_lt(void)
  function mon_pt (line 144) | void mon_pt(void)
  function mon_bp (line 162) | void mon_bp(void)
  function mon_rx (line 182) | void mon_rx(void)
  function mon_or (line 209) | void mon_or(void)
  function mon_adc (line 225) | void mon_adc(void)
  function mon_parse (line 267) | void mon_parse(char* s)
  function mon_evaluate (line 299) | void mon_evaluate(void)

FILE: relay.c
  function relay_setband (line 33) | void relay_setband(int val)
  function relay_getband (line 43) | int relay_getband(void)
  function relay_setattn (line 57) | void relay_setattn(int val)
  function relay_getattn (line 67) | int relay_getattn(void)
  function relay_init (line 81) | void relay_init(void)

FILE: si5351.c
  function si_getvfo (line 213) | int  si_getvfo(int i, vfo_t *v)
  function si_setphase (line 227) | void si_setphase(int i, uint8_t p)
  function si_enable (line 234) | void si_enable(int i, bool en)
  function si_getreg (line 254) | int si_getreg(uint8_t *data, uint8_t reg, uint8_t len)
  function si_setmsn (line 279) | void si_setmsn(int i)
  function si_setmsi (line 320) | void si_setmsi(int i)
  function si_evaluate (line 413) | int si_evaluate(int i, uint32_t freq)
  function si_init (line 460) | void si_init(void)

FILE: si5351.h
  type vfo_t (line 30) | typedef struct

FILE: uSDR.c
  function i2c_put_data (line 41) | int i2c_put_data(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size...
  function i2c_get_data (line 48) | int i2c_get_data(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len...
  type repeating_timer (line 59) | struct repeating_timer
  function led_callback (line 60) | bool led_callback(struct repeating_timer *t)
  type repeating_timer (line 75) | struct repeating_timer
  function loop_callback (line 76) | bool loop_callback(struct repeating_timer *t)
  function main (line 83) | int main()
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (665K chars).
[
  {
    "path": ".github/workflows/cmake.yml",
    "chars": 1401,
    "preview": "name: CMake\n\non:\n  # Trigger the workflow on push or pull request,\n  # but only for the main branch\n  push:\n    branches"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 2274,
    "preview": "# Generated Cmake Pico project file\r\n#\r\n# After changing this file, empty the build folder and execute from there:  \r\n# "
  },
  {
    "path": "README.md",
    "chars": 9237,
    "preview": "![uSDR-Pico 4](https://github.com/ArjanteMarvelde/uSDR-pico/blob/main/doc/uSDR-Pico-4.jpg)  \n\nThe new V4.0 is now availa"
  },
  {
    "path": "dsp.c",
    "chars": 23651,
    "preview": "/*\r\n * dsp.c\r\n *\r\n * Created: Mar 2021\r\n * Author: Arjan te Marvelde\r\n * \r\n * Signal processing of RX and TX branch, to "
  },
  {
    "path": "dsp.h",
    "chars": 1323,
    "preview": "#ifndef __DSP_FFT_H__\n#define __DSP_FFT_H__\n/* \n * dsp.h\n *\n * Created: Mar 2021\n * Author: Arjan te Marvelde\n *\n * See "
  },
  {
    "path": "dsp_fft.c",
    "chars": 14976,
    "preview": "/*\n * dsp_fft.c\n * ==>TO BE INCLUDED IN dsp.c\n *\n * Created: May 2022\n * Author: Arjan te Marvelde\n * \n * Signal process"
  },
  {
    "path": "dsp_tim.c",
    "chars": 7018,
    "preview": "/*\n * dsp_tim.c\n * ==>TO BE INCLUDED IN dsp.c\n *\n * Created: May 2022\n * Author: Arjan te Marvelde\n * \n * Signal process"
  },
  {
    "path": "fix_fft.c",
    "chars": 19543,
    "preview": "/* fix_fft.c - Fixed-point in-place DIT Fast Fourier Transform  */\n/*\n  All data are fixed-point uint16_t integers, in w"
  },
  {
    "path": "fix_fft.h",
    "chars": 337,
    "preview": "#ifndef __FIX_FFT_H__\n#define __FIX_FFT_H__\n/* \n * fix_fft.h\n *\n * Created: Apr 2022\n * Author: Arjan te Marvelde\n *\n * "
  },
  {
    "path": "font16.c",
    "chars": 49632,
    "preview": "/**\n  ******************************************************************************\n  * @file    font16.c\n  * @author  "
  },
  {
    "path": "font20.c",
    "chars": 66353,
    "preview": "/**\n  ******************************************************************************\n  * @file    font20.c\n  * @author  "
  },
  {
    "path": "font24.c",
    "chars": 99002,
    "preview": "/**\n  ******************************************************************************\n  * @file    font24.c\n  * @author  "
  },
  {
    "path": "font7spp.c",
    "chars": 13388,
    "preview": "// font7spp.c\n// Font type    : Special (SubSet)\n// Font size    : 32x50 pixels\n\n#include \"fonts.h\"\n\nconst uint8_t Font7"
  },
  {
    "path": "font8.c",
    "chars": 18291,
    "preview": "/**\n  ******************************************************************************\n  * @file    Font8.c\n  * @author  M"
  },
  {
    "path": "fontAR.c",
    "chars": 23724,
    "preview": "// Arial Round 16x24\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontAR_Table [] =\n{\n0x00,"
  },
  {
    "path": "fontGR.c",
    "chars": 31318,
    "preview": "// Grotesk 16x32\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontGR_Table [] =\n{\n0x00,0x00"
  },
  {
    "path": "fontSYM16.c",
    "chars": 16153,
    "preview": "// Various symbols 16x16\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontSYMs_Table [] =\n{"
  },
  {
    "path": "fontSYM32.c",
    "chars": 61731,
    "preview": "// Various Symbols 32x32\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontSYM_Table [] =\n{\n"
  },
  {
    "path": "fonts.h",
    "chars": 2971,
    "preview": "/**\n  ******************************************************************************\n  * @file    fonts.h\n  * @author  M"
  },
  {
    "path": "fontub.c",
    "chars": 46512,
    "preview": "// Ubuntu 24x32\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontUB_Table [] =\n{\n0x00,0x00,"
  },
  {
    "path": "fontubb.c",
    "chars": 46521,
    "preview": "// Ubuntu bold 24x32\n// Font type    : Full (95 characters)\n\n#include \"fonts.h\"\n\nconst uint8_t FontUBB_Table [] =\n{\n0x00"
  },
  {
    "path": "hmi.c",
    "chars": 21323,
    "preview": "/*\n * hmi.c\n *\n * Created: Apr 2021\n * Author: Arjan te Marvelde\n * \n * This file contains the HMI driver, processing us"
  },
  {
    "path": "hmi.h",
    "chars": 224,
    "preview": "#ifndef __HMI_H__\n#define __HMI_H__\n/* \n * hmi.h\n *\n * Created: Apr 2021\n * Author: Arjan te Marvelde\n *\n * See hmi.c fo"
  },
  {
    "path": "lcd.c",
    "chars": 16540,
    "preview": "/*\r\n * lcd.c\r\n *\r\n * Created: Sep 2024\r\n * Author: Arjan te Marvelde\r\n * \r\n *\r\n * This file contains the driver for a Wa"
  },
  {
    "path": "lcd.h",
    "chars": 7068,
    "preview": "#ifndef __LCD_H__\n#define __LCD_H__\n/* \n * lcd.h\n *\n * Created: Sep 2024\n * Author: Arjan te Marvelde\n *\n * See lcd.c fo"
  },
  {
    "path": "monitor.c",
    "chars": 7676,
    "preview": "/*\n * monitor.c\n *\n * Created: Mar 2021\n * Author: Arjan te Marvelde\n * \n * Command shell on stdin/stdout.\n * Collects c"
  },
  {
    "path": "monitor.h",
    "chars": 210,
    "preview": "#ifndef __MONITOR_H__\n#define __MONITOR_H__\n/* \n * monitor.h\n *\n * Created: Mar 2021\n * Author: Arjan te Marvelde\n *\n * "
  },
  {
    "path": "relay.c",
    "chars": 1815,
    "preview": "/*\n * relay.c\n *\n * Created: Nov 2021\n * Author: Arjan te Marvelde\n * \n * Two PCF8574 expanders are on the I2C bus, one "
  },
  {
    "path": "relay.h",
    "chars": 587,
    "preview": "#ifndef __RELAY_H__\n#define __RELAY_H__\n/* \n * relay.h\n *\n * Created: Nov 2021\n * Author: Arjan te Marvelde\n *\n * See re"
  },
  {
    "path": "si5351.c",
    "chars": 18050,
    "preview": "/*\r\n * si5351.c\r\n *\r\n * Created: Jan 2020\r\n * Author: Arjan\r\n *\r\n * Driver for the SI5351A VCO\r\n *\r\n * Provides \r\n * - V"
  },
  {
    "path": "si5351.h",
    "chars": 1307,
    "preview": "#ifndef _SI5351_H\r\n#define _SI5351_H\r\n/*\r\n * si5351.h\r\n *\r\n * Created: March 2021\r\n * Author: Arjan\r\n *\r\n * Driver for S"
  },
  {
    "path": "uSDR.c",
    "chars": 4131,
    "preview": "/*\r\n * uSDR.c\r\n *\r\n * Created: Mar 2021\r\n * Author: Arjan te Marvelde\r\n * \r\n * The main loop of the application.\r\n * Thi"
  },
  {
    "path": "uSDR.h",
    "chars": 3801,
    "preview": "#ifndef __USDR_H__\n#define __USDR_H__\n/* \n * uSDR.h\n *\n * Created: Aug 2022\n * Author: Arjan te Marvelde\n *\n * This file"
  }
]

About this extraction

This page contains the full source code of the ArjanteMarvelde/uSDR-pico GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (623.1 KB), approximately 373.0k tokens, and a symbol index with 66 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!