Compare commits

...

43 Commits

Author SHA1 Message Date
Markus Koch c2836688d1 doc: Add arrow on architecture drawing 2020-05-18 21:13:15 +02:00
Markus Koch 781a02dce6 Add printer scripts 2020-05-16 16:29:32 +02:00
Markus Koch 8c950a02ea Fix more bugs 2020-05-16 16:27:38 +02:00
Markus Koch 97a9f9f402 Add links to blog posts 2020-05-13 14:12:18 +02:00
Markus Koch 5ebb104e19 Implement special commands and fix some bugs
Note: Special commands are currently broken in backwards mode!
Do not use them when the buffer is not empty!
2020-05-13 14:08:41 +02:00
Markus Koch 446b6102ac display: Add new splashscreen 2020-05-10 20:48:01 +02:00
Markus Koch 323fa68222 printer:avr: Fix startup behavior if in correction mode
Also introduce startup wait until 0xFF is received.
2020-05-10 20:43:53 +02:00
Markus Koch 0ec64e6a39 ioc:kernel-driver: Fix startup delay for normal mode 2020-05-10 20:41:10 +02:00
Markus Koch 3ae19dc20a display:fpga: Fix project file 2020-05-10 20:40:08 +02:00
Markus Koch eebd6e5517 doc: Add HW architecture diagram 2020-05-10 20:36:53 +02:00
Markus Koch b2502e7f0a printer: avr: Implement protocol with kernel driver 2020-01-03 17:02:08 +01:00
Markus Koch fe2363cfdf ioc: Add CMakeLists for lw35-tool 2020-01-03 16:47:29 +01:00
Markus Koch b8a5ae2fcd keyboard: Fix ring buffer for printer packet forwarding 2020-01-03 16:46:14 +01:00
Markus Koch d588eeee42 ioc: Implement printer buffer handling in kernel driver 2020-01-03 16:45:28 +01:00
Markus Koch 7a7399a602 keyboard: avr: Forward printer UART packets 2019-12-27 23:13:51 +01:00
Markus Koch 7269db9e0a ioc: avr: Add make rfu command to AVR Makefiles 2019-12-27 22:41:17 +01:00
Markus Koch 0da970d40f ioc: lw35-tool: Add tool to configure IOC mode 2019-11-16 21:24:58 +01:00
Markus Koch 6e1a771862 ioc: kernel-driver: Add IOC charecter device 2019-11-16 21:22:34 +01:00
Markus Koch 101117d0bc ioc: Add reset GPIO 2019-11-16 13:22:22 +01:00
Markus Koch b23252df95 printer: avr: Extend test program to test main printer code
Also, cleanup.
2019-11-11 18:17:21 +01:00
Markus Koch 14216b3888 ioc: avr-bootloader: Add Y command to bypass the subsequent device to bypass
Note: Uncommented delay loop at beginning because of
code size limit.
2019-11-11 16:47:24 +01:00
Markus Koch 9a896c3314 printer: avr: Extend test mode 2019-11-10 20:12:26 +01:00
Markus Koch d3997d6049 ioc: bootloader: Wait for only about a second 2019-11-10 19:59:41 +01:00
Markus Koch f2ba588a46 ioc: kernel-driver: Update baudrate to 19200 2019-11-10 19:49:32 +01:00
Markus Koch b4bc651445 ioc: bootloader: Disable LED, add X and Z commands, clean up 2019-11-10 19:48:24 +01:00
Markus Koch 1be8f62f3e ioc: avr: Set IOC baudrates to 19200 2019-11-10 19:44:24 +01:00
Markus Koch 35268c53ae printer: avr: Update to new hardware
* Update I/O constraints
* Remove SPI code (some left for future reference)
* Launch test code instead of printer program
2019-11-10 18:11:09 +01:00
Markus Koch df2ec0cb17 printer: Remove accidentally committed file 2019-11-10 13:31:02 +01:00
Markus Koch 00792df17b ioc: Add basic bootloader for both IOCs 2019-11-10 13:30:17 +01:00
Markus Koch 9e41c88c5b env: Update gitignore 2019-11-10 13:29:30 +01:00
Markus Koch 4f8931f193 keyboard: avr: Do not send an event on FN 2019-11-01 19:52:44 +01:00
Markus Koch 2b070b173a keyboard: avr: implement ioc protocol 2019-11-01 19:52:17 +01:00
Markus Koch 13d25c6866 ioc: kernel-driver: implement keyboard driver 2019-11-01 19:51:37 +01:00
Markus Koch 1e4ba2c739 display: kernel-driver: rework color-to-bw conversion 2019-11-01 19:51:10 +01:00
Markus Koch f0f671c6fb ioc: kernel-driver: Create framework for serdev driver 2019-11-01 12:53:12 +01:00
Markus Koch 465dbf8c79 display: kernel-driver: update to latest kernel and new file structure 2019-11-01 11:30:04 +01:00
Markus Koch 90203f56cf keyboard: Change keycode for print to also use sysrq 2019-10-26 22:47:36 +02:00
Markus Koch 4ea322e2f5 keyboard: add ATmega8 define to QtProject for indexing 2019-10-26 22:41:52 +02:00
Markus Koch 7479c9ed3f keyboard: dynamically derive UBRR values from BAUDRATE 2019-10-26 22:38:51 +02:00
Markus Koch 9bed136cd5 keyboard: Use serial bootloader in Makefile 2019-10-26 22:31:21 +02:00
Markus Koch 45e606797b keyboard: Map keys 2019-10-26 22:31:05 +02:00
Markus Koch 014f28478b keyboard: Add arduino serial bootloader 2019-10-26 19:03:54 +02:00
Markus Koch 37cfd93bef printer: implement SPI based controller 2019-10-26 17:11:07 +02:00
45 changed files with 2783 additions and 2940 deletions

26
.gitignore vendored
View File

@ -1 +1,25 @@
doc
# AVR temp files
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin
*.obj
# Linux kernel driver temp files
.cache.mk
*.cmd
.tmp_versions/*
*.a
*.mod
# Qt files
build-*
# CMake
**/CMakeFiles/**
CMakeCache.txt
cmake_install.cmake

View File

@ -1,4 +1,10 @@
# Brother LW-35 Modernization
Drivers, firmware and tools used in my LW-35 electronic typewriter modernization.
Documentation coming soon-ish.
For documentation, see my Vlog series:
* [Part 1: LCD](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-1)
* [Part 2: Keyboard](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-2)
* [Part 3: Printer preparation](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-3)
* [Part 4: Printer](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-4)
* [Part 5: Bringing it all together](https://notsyncing.net/?p=blog&b=2020.lw35-vlog-5)

View File

@ -2,7 +2,7 @@
<BaliProject version="3.2" title="lmg6202" device="LCMXO2-1200HC-5SG32C" default_implementation="impl1">
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="Strategy1">
<Options def_top="design.top" top="design.top"/>
<Options def_top="design.top" lib="design" top="design.top"/>
<Source name="../ip/gram0/gram0.ipx" type="IPX_Module" type_short="IPX">
<Options/>
</Source>
@ -18,6 +18,12 @@
<Source name="../design/spi_if.vhd" type="VHDL" type_short="VHDL">
<Options lib="design"/>
</Source>
<Source name="../ip/pll0/pll0.vhd" type="VHDL" type_short="VHDL">
<Options lib="ip"/>
</Source>
<Source name="../generics/synchronizer.vhd" type="VHDL" type_short="VHDL">
<Options lib="generics"/>
</Source>
<Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
<Options/>
</Source>

View File

@ -190,7 +190,7 @@
<Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
<Property name="PROP_SYN_UseLPF" value="True" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="False" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="True" time="0"/>
<Property name="PROP_THERMAL_DefaultFreq" value="0" time="0"/>
<Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
<Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>

View File

@ -1,3 +0,0 @@
Date=04/22/2018
Time=17:34:06

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<DiamondModule name="gram0" module="gram0" VendorName="Lattice Semiconductor Corporation" generator="IPexpress" date="2018 04 22 11:42:01.314" version="7.5" type="Module" synthesis="synplify" source_format="VHDL">
<DiamondModule name="gram0" module="gram0" VendorName="Lattice Semiconductor Corporation" generator="IPexpress" date="2020 05 10 12:58:23.793" version="7.5" type="Module" synthesis="synplify" source_format="VHDL">
<Package>
<File name="" type="mem" modified="2018 04 22 11:42:01.000"/>
<File name="gram0.lpc" type="lpc" modified="2018 04 22 11:42:00.000"/>
<File name="gram0.vhd" type="top_level_vhdl" modified="2018 04 22 11:42:00.000"/>
<File name="gram0_tmpl.vhd" type="template_vhdl" modified="2018 04 22 11:42:00.000"/>
<File name="tb_gram0_tmpl.vhd" type="testbench_vhdl" modified="2018 04 22 11:42:00.000"/>
<File name="/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem" type="mem" modified="2020 05 10 12:46:45.000"/>
<File name="gram0.lpc" type="lpc" modified="2020 05 10 12:58:21.000"/>
<File name="gram0.vhd" type="top_level_vhdl" modified="2020 05 10 12:58:21.000"/>
<File name="gram0_tmpl.vhd" type="template_vhdl" modified="2020 05 10 12:58:21.000"/>
<File name="tb_gram0_tmpl.vhd" type="testbench_vhdl" modified="2020 05 10 12:58:21.000"/>
</Package>
</DiamondModule>

View File

@ -16,8 +16,8 @@ CoreRevision=7.5
ModuleName=gram0
SourceFormat=VHDL
ParameterFileVersion=1.0
Date=04/22/2018
Time=17:34:06
Date=05/10/2020
Time=13:18:44
[Parameters]
Verilog=0
@ -41,7 +41,7 @@ Optimization=Speed
Reset=Sync
Reset1=Sync
Init=mem
MemFile=/home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
MemFile=/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
MemFormat=bin
EnECC=0
Pipeline=0
@ -50,7 +50,7 @@ WriteB=Normal
init_data=0
[FilesGenerated]
/home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem=mem
/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem=mem
[Command]
cmd_line= -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
cmd_line= -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL

View File

@ -1,5 +1,5 @@
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun Apr 22 17:34:06 2018
Sun May 10 13:18:44 2020
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -7,7 +7,7 @@ Copyright (c) 1995-2001 Lucent Technologies Inc. All rights reserved.
Copyright (c) 2001 Agere Systems All rights reserved.
Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -15,7 +15,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,8 +1,8 @@
-- VHDL netlist generated by SCUBA Diamond (64-bit) 3.10.0.111.2
-- Module Version: 7.5
--/usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type bram -wp 11 -rp 1010 -data_width 9 -rdata_width 9 -num_rows 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
--/usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type bram -wp 11 -rp 1010 -data_width 9 -rdata_width 9 -num_rows 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
-- Sun Apr 22 17:34:06 2018
-- Sun May 10 13:18:44 2020
library IEEE;
use IEEE.std_logic_1164.all;
@ -265,19 +265,19 @@ architecture Structure of gram0 is
attribute MEM_INIT_FILE : string;
attribute GSR : string;
attribute MEM_LPC_FILE of gram0_0_0_6 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_0_0_6 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_0_0_6 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_1_0_5 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_1_0_5 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_1_0_5 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_2_0_4 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_2_0_4 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_2_0_4 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_3_0_3 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_3_0_3 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_3_0_3 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_4_0_2 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_4_0_2 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_4_0_2 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_5_0_1 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_5_0_1 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_5_0_1 : label is "splash.mem";
attribute MEM_LPC_FILE of gram0_6_0_0 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_6_0_0 : label is "gram_init.mem";
attribute MEM_INIT_FILE of gram0_6_0_0 : label is "splash.mem";
attribute GSR of FF_11 : label is "ENABLED";
attribute GSR of FF_10 : label is "ENABLED";
attribute GSR of FF_9 : label is "ENABLED";
@ -309,15 +309,15 @@ begin
gram0_0_0_6: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1F=> "0x0F800000003E00000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x000000000000000000000000000000000000000000000000000010007C00001E000C000000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x000000000000000000000000000180006013821F0000000000000000000000000000000000000000",
INITVAL_1B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x001FC03DF80060100201000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x0000000000000000000000000000000000000000000000000000000001FE3FE03002010000000000",
INITVAL_18=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x000000000000000000000000000000200FE000000000000000000000000000000000000000000000",
INITVAL_16=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
@ -374,37 +374,37 @@ begin
gram0_1_0_5: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x0020100201000003F07E001F83FDFE3FBFE3FDC03FEFF00201000000000000000000003FC1E00000",
INITVAL_1E=> "0x001F03FC3E3F87E000003E0FE00000000003C1FE00000001FC3FE0F0020100000001C00FE01303FF",
INITVAL_1D=> "0x3FFC13FFFF3C3FF3FE0F00000000000000000000001F03FC00000003F1FE03FC13FE07001803FC0E",
INITVAL_1C=> "0x00000001003FE01002013F9FE0FC000000000000381FE00C003FDFF03FFD3FE0F3FFFF00E0100201",
INITVAL_1B=> "0x00000001FC3FFFF3FFFF303FF3FFFF3FEFF003FD207FF3FFFF3FFFF07FFF3FFFF3FFFF00F813FFFF",
INITVAL_1A=> "0x0020100000000003F83E001FC3FDFE3FDFE1FDE03FE7F0020100000000003FDFE3FDFE3FE1F3F3FF",
INITVAL_19=> "0x3FFFF3FE033F83E3F1FE3FFFF3FFFF3FFFF3FDFF3FEFF003F93FE030020100000001C007E01383FF",
INITVAL_18=> "0x3FFE13FFFF3C3FF3FE060000000000001E03FDFE3FFFF1FF813FFFF3FFFF003E13FF833FFFF3FFFF",
INITVAL_17=> "0x3FFF73FFFF3FFFF3FE0F3F1FE03C0000000000003C1FE004003FDFF01FFF3FF0F3FFFF00E0100201",
INITVAL_16=> "0x00000001FE3FFFF3FFFF383FF3FFFE3FE0F003FF307FF3FFFF3FFFF27FFF3FFFF3FFFF00F013FEFF",
INITVAL_15=> "0x0000000000000003FC1E001FE3FCFE3FDFE0FDF03FE3F0020100000000003FDFE3FDFF3FE0F3FBFF",
INITVAL_14=> "0x3FFFF07E013FC1E3F1FE3FFFF3FFFF3FFFE3FDFF3FE7F003F10FE010020100000001E003E013C3FF",
INITVAL_13=> "0x1FFF13FFFF3F3FF3FC020000000000001F03FDFE3FFFF0FFC13FFFF3FEFF001E03FDC03FFFF3FFFF",
INITVAL_12=> "0x3FFFB3FFFF3FFFF3FE073E1FE00C0000000000003C1FE000003FFFF21FFF3FF873FFFF0060100201",
INITVAL_11=> "0x00000201FE3FFFF3FFFF383FF3FDFE03E01203FF383FF3FFFF3FFFF37FFF3FFFF3FFFF00F013FE3F",
INITVAL_10=> "0x0000000000001003FC1E001FE3FC7E3FDFE0FDF93FE3F0020100000000003FDFE3FDFF3FE073FBFF",
INITVAL_0F=> "0x3FE3F002013FC1E3F9FF3FFFF3FFFF3FDFE3FFFF3FE3F003E103E010020100000001F001E013C3FF",
INITVAL_0E=> "0x0FFF13FFFF3F3FE3FC000000000000001F03FDFE3FFFF07FC13FFFF07E01001E01FD803FFFF3FFFF",
INITVAL_0D=> "0x3FFF13FFFF3FFFF3FE033C0FE0000000000000003C0FE000003FDFF007FF3FF013FFFF0020100200",
INITVAL_1F=> "0x01E013F2FB201DE01C0000000303871C10000C18002011C2010000000000200FE000003E00E00000",
INITVAL_1E=> "0x3F0063FC063F80E380FE301FE001FE003F101DFC003F903E003FC7E001801FE013E2FD0003800000",
INITVAL_1D=> "0x30383007E10187C000000020100000000003E00E001001FDC03FFFF0FFC103FF10FE013FC033FE0F",
INITVAL_1C=> "0x3F9FE3FCFE3F03E3C0FE001E03FC02301FE00D001FA0120207300063E01E3007E2000E2000600000",
INITVAL_1B=> "0x000000010001E01003F1383FF3FFFE303FF3FDFE003F83FDFE00FC13FFFF1FF013FFFF0FE01003FF",
INITVAL_1A=> "0x006013F27F201FE01C0000C000FC00004013820307C00060000000000000200FE000003E00E3FDFE",
INITVAL_19=> "0x3FE073F3FF3FE01203FF3FE3F003F93FFFF01FF13FFFF006013F81E0018007E013E2FF000E0000F0",
INITVAL_18=> "0x0020100200001F801D800020000000000003E006001000FDE03FFFF07E013FFFF01E013FDFE3FC00",
INITVAL_17=> "0x3E1FE3FC7E381FE3FC1E001C03FC00301FE005000FE010020D0781C0000000000381E23020000000",
INITVAL_16=> "0x000000018000E01003F93C3FF3FDFE003FC3FC3E001803FDFE002013F9FE0FE013F3FF00E01003FD",
INITVAL_15=> "0x002013FA1E201FE00C00038F03000200000000003020701A0000000000003007E000003F0063FDFE",
INITVAL_14=> "0x3FE03203FF01E01003F13FE01002013FFFF00E013FE1F002013F80E001C003E013E27F0018038006",
INITVAL_13=> "0x01C0000001200063C0E000000000000000000000000000000000000000003F01E00000201FE00400",
INITVAL_12=> "0x0000000000001F007C0000000000000000000000000000003000FC10060100000079000CE0100201",
INITVAL_11=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_10=> "0x000000000000000000003E0E60007800000001F0301F200C00000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000007C1C",
INITVAL_0E=> "0x3C000000000F8000383C000000000000000000000000000000000000000000000000000000000000",
INITVAL_0D=> "0x000000000000000000000000000000000000000000000000E0070001F000001F0001E00600000000",
INITVAL_0C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x000000000000000000000010000C0000E013E2070E00000000000000000000000000000000000000",
INITVAL_0A=> "0x000000000000000000000000000000000000000000000000000000000000000000000000000001E0",
INITVAL_09=> "0x001F83FDFE0038100600000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x0000000000000000000000000000000000000000000000000038002001F83FE010021F0000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x00000000000000000000000001E0000003E0000001C0000001000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_04=> "0x00201002010003C00000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x000000000000000000000000000000000000000000000000000007800000000003E0000000000000",
INITVAL_02=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_01=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_01=> "0x00000000000000000000000002001E00000001C00020100000000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
CSDECODE_B=> "0b001", CSDECODE_A=> "0b001", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
@ -439,38 +439,38 @@ begin
gram0_2_0_4: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000003F83E000003FFFF3FFFF01E0100201001F01FC003E1FE3FD823FFFF387FF1FE0100201",
INITVAL_1E=> "0x000000000000000001C007E0100201001E03FD801FE01002013FE0100201001C03FC02001FE3FDFE",
INITVAL_1D=> "0x3FEFF0020100000301FE003813FFFE307FF3FE1F3FDFF01E0100000000000000000000381FE00400",
INITVAL_1C=> "0x00000001FE303FF01E01201FE03C0000000001FE006013C3FF3FFFF3FE0700000000003FC0E003F9",
INITVAL_1B=> "0x3FE3F3FBFF03FFD3FEFF000000000000000381FE3FFFF3FE3F00000000003FC1E3F07E000003E1FE",
INITVAL_1A=> "0x00000000003FC3E000003FDFF3FFFF0060100201001F80FC003F1FE3FDC23FFFF383FF1FE0100201",
INITVAL_19=> "0x00000000003FFFF3FFFF07E0100201001E03FD800FE01003011FE0100201001E03FC00001FC0FC00",
INITVAL_18=> "0x3FC1E0020100000301FE003813FDFE383FF3FE1F3FDFF00E010000000000001FE3FDFE3FFFF00201",
INITVAL_17=> "0x00000201FE383FF00E01201FE01C0000000001FE00201383FF003F91FC0000000000003FC07003F1",
INITVAL_16=> "0x3FE0F3F3FF01E01002010000000000000003E1FE3FFFF3FE1F00000000003FC1E3F87F000003F0FE",
INITVAL_15=> "0x00000000003FC1E000013FC06383FF0020100200001FC07C00000000000000000000000000000000",
INITVAL_14=> "0x00000001003FFFF3FFFF03E0100201001F01FDC007E01003811FE0100201001F03FC00001F81FC00",
INITVAL_13=> "0x3FE070020100000381FE0020000000000000000000000000000000000000201FE3FDFE3FEFF00201",
INITVAL_12=> "0x00000201FE383FF00600301FE00C0000000201FE00201303FE203FF07E0000000000003FC0300201",
INITVAL_11=> "0x000000000000000000000000000000000003E1FE3FFFF3FE0F00000000003FC0E3FE3F000003F07E",
INITVAL_10=> "0x00000000003FC0E000013FC0E3E3FF0000000000001FE07C00000000000000000000000000000000",
INITVAL_0F=> "0x00000001003FFFF3FFFF01E0100201001F80FDE007E01003C10FE0100201001F81FC00001F01FD80",
INITVAL_0E=> "0x1FE0100201000003C1FE001C03FDFE3C3FF3FC023FEFF002010000000000201FE3FDFE3FEFF00201",
INITVAL_0D=> "0x00000381FE3C3FF00000381FE0040000000301FE00201203FE383FF01E0100000000003FE01003FF",
INITVAL_0C=> "0x3FF073FFFF20FFF3FE1F00000000000000000000001803FC0600000000003FD073FE1F000003F83E",
INITVAL_0B=> "0x00000000003FC06002013FC1E3FC7F0000000000201FE03C003FDFE0FDF03FE7F3F3FF03E0100201",
INITVAL_0A=> "0x000000000000000001F800E0100201001FE07DF003E01003C107E0100201001F80FC00001F03FDF0",
INITVAL_09=> "0x07E0100201000003E1FE001F03FDFE3E3FF3FD823FFFF00201000000000000000000003F87E00000",
INITVAL_08=> "0x000003E1FE3E3FE000003C1FE0040000000381FE00201001FE3E3FF0020100000001001FE01203FF",
INITVAL_07=> "0x3FF873FFFF307FF3FE1F00000000000000000000001C03FC0600000001003FF013FE0F000003FC1E",
INITVAL_06=> "0x00000000003FC03002013FD9E3FC0E0000000000201FE01C003FDFE0FDF93FE3F3F3FF03E0100201",
INITVAL_05=> "0x000000000000000001FC0060100201301FE03DF801E01003E103E0100201001FC07C00001E03FDFE",
INITVAL_04=> "0x01E0100201000003F0FE001F03FDFE3F3FE3FDC23FFFF00201000000000000000000003F83E00000",
INITVAL_03=> "0x000003F8FE3F0FE000003E1FE0000000000381FE00200001FE3FE7F0020100000001801FE01303FF",
INITVAL_02=> "0x3FF833FFFF383FF3FE0F00000000000000000000001E03FC0200000001F00FF813FE0F001003FC1E",
INITVAL_01=> "0x00000000003FE03002013F9FE3FC020000000000301FE00C003FDFE07FFD3FE1F3FBFF01E0100201",
INITVAL_00=> "0x000000000000000001FE00601002013F9FE005F800E01003F101E0100201001FE03C00001C03FDFE",
INITVAL_1F=> "0x003FE001F02020F003C0007FD3FFFF007F9207DF3C20F000062000324202000670020F0040600001",
INITVAL_1E=> "0x00000000001FC000010101E010038100E310020103FFD006013F8023C01E3E00E0C0003803E381FE",
INITVAL_1D=> "0x3FE3F3023F3BC0E1FE0100C0C1C10000E000C00400C380C0010000000000001F001C00200FE00000",
INITVAL_1C=> "0x3007E00000001FE3803E001C007C0007D011FE01000003F8023FDFF3FE0107CF81FBE10026118200",
INITVAL_1B=> "0x200430030101A1C301000020100000000002007E000003E006000003F002000003C01E03E01003FD",
INITVAL_1A=> "0x003FC005F000201001C0007FD3FFFF003F9387CF3C20700206060F10220C200C01E0602000200201",
INITVAL_19=> "0x00000000000FC000038100E01003C1006010020103FFF002013F802301FE3FE07002013803E381FE",
INITVAL_18=> "0x3FE0F3821F38D0F0FE0100D9C00DFC03000031F83E218060000000000000001F800C003007E00000",
INITVAL_17=> "0x3803E00000001FE3C01E001C007C003FDFF0FE01000003F80207D000FE0103C7F1FBF1002E13007E",
INITVAL_16=> "0x3C186000C00FD003FD000020000000000003007E000003F0063FDFF3FE03000003C11E03E01003FD",
INITVAL_15=> "0x303FE3FDFE00201001C0007F9007F9003FD3C1C23E2070020C1CC003F27F3C1FE001382020300201",
INITVAL_14=> "0x00000000000FC000038100FFD3FFFF006010020123EFF002013F8023FDFE3FE07002013803E3003E",
INITVAL_13=> "0x3F0023811E3070F0FE010183E018803FDFE0FC100303C060000000000000001F8004003003E381FE",
INITVAL_12=> "0x3FE1F00201001FE3E00E001C007DF03FFFF07E01000003F80207DC007E0123C1F1F3F1002C01E1C0",
INITVAL_11=> "0x1800001C30021C03018E0000000000000003803E000003F8023FDFF3FE01000003C11E01E01003FD",
INITVAL_10=> "0x3F3FE3FDFE00200001C0007F9007FD000FE3F1803F203003DC30200018C0031000040E33C0000000",
INITVAL_0F=> "0x000000000007C01003C1007FD3FFFF002010020123EFF002013F9C21FC003F802000003803E3003E",
INITVAL_0E=> "0x3FC003C18E3038F07E013F000060C0301800003000D8003C000000000000001FC004003803E3C1FE",
INITVAL_0D=> "0x3FE1F00201001FE3E00E001C007DFE003C007C00000003F8020FDE001C0139E0F3F3F9003C000D00",
INITVAL_0C=> "0x082010600C06070001E00000000000000003803E000003F802000003FC00000003E10E01E01003FF",
INITVAL_0B=> "0x3FC00001FC00200001E0003F120EFF000FE1F9803F2030021F000060080000F01204023800600000",
INITVAL_0A=> "0x000000000007C01003C100601003E1002010030121EFF002013FDE003C003F800000003C01E2007E",
INITVAL_09=> "0x0FC003C1EF3039F07C0000C001C2410003E00030004001E2010000000000001FE000003C01E00000",
INITVAL_08=> "0x3C00E00000200FE3E00E001E003CFE001E003C00000003FC000FDF8005013CE073F3FD0003E00000",
INITVAL_07=> "0x080013820006018000000040100201000003C01E000003FC00001001FC00000003F10601E01202FF",
INITVAL_06=> "0x1FC00001FF00000001F0003F130E3E2017E07D803FA011C2010001C0080000501186010003800000",
INITVAL_05=> "0x000000000003E01003E100201003F12020F003C020FFF002011FDF001E013FC0003C003F00E2007E",
INITVAL_04=> "0x03C013E3F7303DE03C000020130240000760003000201302020000000000001FE000003C01E00000",
INITVAL_03=> "0x3E10E1FC003803E3C01E001F820CFE001E003DFE001800FC001FDFC001003EE013E3FD0000C00000",
INITVAL_02=> "0x184000600F06006000000000000201000003C01E000003FC00001001FDE0002013FE0307E013827F",
INITVAL_01=> "0x3FC00001FE3F802001FC003E13DC0E201FE03D003FA013820100070019C0031000E0000001C00000",
INITVAL_00=> "0x000000000001E01003E100201003F03C23F001F0003FF0060107FE107E011FDC00FC003FC02000FE",
CSDECODE_B=> "0b010", CSDECODE_A=> "0b010", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -504,38 +504,38 @@ begin
gram0_3_0_3: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000003FDFE3FDFF3FE013FBFF0FE01002013FC06000003F80E00000000003F01E381FE00000",
INITVAL_1B=> "0x000003FD063FFFF3FFFF00E0100201000000000000000000000000000000001F83FDFE3FFFF07FE1",
INITVAL_1A=> "0x3FFFF1FE01001F01FC00001E03FC0000000001C007E013FE3F00000001F021FFF3FFFF3FEFF00201",
INITVAL_19=> "0x00000000000000000000000000000000000381FE3FFFF3FFFF3C3FE3FDFE00E01203FF00201003FE",
INITVAL_18=> "0x0020100201381FE005E007E01002013F0FE3F1FE3FFFF3FE0F201FE3FC1E3FDFE01FF93FE0700201",
INITVAL_17=> "0x00000000003FDFF3FFFF3FE033FFFF3FFFF002013FC0E002013FC1E00000000003F83E3C1FE00400",
INITVAL_16=> "0x001C03FD8E3FFFF3FFFF01E013F3FF07FFD3FFFF3F9FE1FC000000000000001FC3FDFE3FFFF07FF1",
INITVAL_15=> "0x3FFFF3FE7F001F81FC00001F03FC0000000001E007E013FA3F00000001FE30FFF3FFFF3FE7F00381",
INITVAL_14=> "0x3FFFF387FF3FFC13FFFF002010020000000381FE3FFFF3FFFF3E3FE3FDFE1FE01303FF00201201FE",
INITVAL_13=> "0x00201002003C1FE005C00FE01002013FC3E3F9FF3FFFF3FE07301FE3FC1E3FDFF03FFF3FE0700201",
INITVAL_12=> "0x00000000003FFFF3FFFF3FF013FFFF3FFFF03E013FC07002013FC0E00001000003FC1E381FE00C00",
INITVAL_11=> "0x001F03FDC03FFFF3FFFF00E013FBFF03FFD3FEFF3FDFE0FC000000000000001FE3FDFE3FFFF03FF1",
INITVAL_10=> "0x3FFFF3FFFF003FC0FC00001F01FC0000000001E003E013FA7F00000301FE383FF3FFFF3FE7F003C1",
INITVAL_0F=> "0x3FFFF3C3FF1FFE13FFFF0020100000000003C1FE3FFFF3FFFF3E1FE3FDFE3FE07383FF00201301FE",
INITVAL_0E=> "0x00201002003E1FE001800FE01002013FC0F3FBFF3FFFF3FE03381FE3FC1E3FFFF01FFF3FE0700201",
INITVAL_0D=> "0x00000000003FDFE3FFFF3FE013FFFF3FFFF0FE013FC03002013FC0600201001003FC0E301FE01C00",
INITVAL_0C=> "0x001FE0FD003FFFF3FFFF006013FBFF01FFF3FEFF3FDFE07C0100000000000000000000201FE01C00",
INITVAL_0B=> "0x000003F1FE003FF07E00001F80FC0000000001F001E013F2FF000003E1FE00200000003FC3E001E0",
INITVAL_0A=> "0x3FEFF3C3FF0FFF13FFFF00200000000000000000000003E0FE00000000003FE0F3C3FF00200381FE",
INITVAL_09=> "0x00201000003E0FE001801FE01003013FE0100201001E03FC023C1FE3FD0E3FFFF20FFF3FE0300201",
INITVAL_08=> "0x000000000000000001801FE0100201001F81FC003FE03002013FC0700201001803FC0E201FE3FDFE",
INITVAL_07=> "0x3FFFF03E0100000001FE002013FFFF21FFF3FE7F3FDFE07C0100000000000000000000301FE01C00",
INITVAL_06=> "0x00000201FE003FF03E01001FC07C0000000001F800E013E3FF3FFFF3FEFF00000000003FC1E001E0",
INITVAL_05=> "0x3FE7F3E3FF0FFF93FFFF00000000000000000000000003F07E00000000003FC1E3E1FF00000381FE",
INITVAL_04=> "0x00200000003F07E001003FFFF3FFFF0FE0100201001F03FC003E1FE3FD063FFFF307FF3FE0100201",
INITVAL_03=> "0x000000000000000001800FE0100201001E03FD003FE01002013FE0300201001C03FC06201FE3FDFE",
INITVAL_02=> "0x3FFFF0060100000201FE003013FFFF30FFF3FE3F3FDFE03E0100000000000000000000381FE00C00",
INITVAL_01=> "0x00000001FE203FF01E01001FE07C0000000001FC00E013C3FF3FFFF3FE1F00000000003FC0E001F1",
INITVAL_00=> "0x3FE7F3F3FF07FF93FFFF00000000000000000000000003F87E00000000003FC1E3E0FE000003C1FE",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000018000006",
INITVAL_1E=> "0x080000600C060000C1C0000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x0000000000000000000000000000000000000000000000001800C000198103100004003020100000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1B=> "0x0000000000000000000003830000C018100004100000E03000000000000000000000000000000000",
INITVAL_1A=> "0x0000000000000000000000000000000000000000000000000000000000000000000000000C020002",
INITVAL_19=> "0x1800031C700200018180000000000000000000000000000000000000000000000000000000000000",
INITVAL_18=> "0x0000000000000000000000000000000000000000000000000C00000213FF3FF8F002012000300200",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_16=> "0x0000000000000000000001818001C007E013FE1F0001C06000000000000000000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000006030000",
INITVAL_14=> "0x3E182000C00F80030100002000000000000000000000000000000000000000000000000000000000",
INITVAL_13=> "0x00000000000000000000000000000000000000000000000006001E1036193008007C002000200201",
INITVAL_12=> "0x000000000000000000000000000000000003E03E00000001FE002010000000000001E000E0100201",
INITVAL_11=> "0x0000000000000000000000C0C30106018000610C002190620000000001C03FFFF07FFD3FFFF307FF",
INITVAL_10=> "0x3FFFF003E13FE01002013FE3F003F1002013FA033F9FE0050001E01202FF1FC0007D800066118201",
INITVAL_0F=> "0x200630030101A3C301000020100000381FE3FDFE3FBFE3FC3E3FDFF3FE1F3F1FE0FC00301FE3FC0E",
INITVAL_0E=> "0x3E01E001C0007F13FEFF200FE000000FDE001FF13023F00006000070620600046200060040600201",
INITVAL_0D=> "0x000003F9FE3FFC33FFFF07FFD3FFFF03FE13FFFF002013FBFE03E013FE013803E381FE3FE013E20F",
INITVAL_0C=> "0x001F800CFE3E0063F00200C0C060000063C0C007018300C00000000001C03FFFF03FFD3FFFF383FF",
INITVAL_0B=> "0x3FEFF203FF3FE1F003F13FFFF007E1006013FA013FFFF07E0101E013823F1FD800FDC00026118381",
INITVAL_0A=> "0x000363E006005812020200201000003C1FE3FDFE3FDFE3FC1E3FDFF3FE0F3FDFE3FE033F1FE3FC7E",
INITVAL_09=> "0x3803E001E0203FF3FFFF002FF0000007DF100FF93821F00006100013830001E3D002190040600001",
INITVAL_08=> "0x000003FDFE3FFE13FFFF03FFD3FFFF01FFD03FF100FC13FE031FE013FA073C01E3F03E3FC0E3C00E",
INITVAL_07=> "0x001FE2007E3F8063F80000C0C01800300FF30203020300C0000000000000001E003C00001FE00000",
INITVAL_06=> "0x200FE3C07E380FE001FE003F901D8000E013FFC101F813FE0103E013C20F0FDC00FDC100261182C1",
INITVAL_05=> "0x0000C3F00E0010020203002010000000000001FE000003C01E000003E00E03E013F20F3FC02201FF",
INITVAL_04=> "0x300FE001E03823F003F1003FF0030101FF100FFF3821F00006180013830001E39002110040600001",
INITVAL_03=> "0x00000000001FC000000001E010030120EFF0030101FF103E013FC003E00E3C00E3FC003C01E3C01E",
INITVAL_02=> "0x3007E2007E3FC061F80000C0C01000200FF38203030300C0000000000000001F001C00200FE00000",
INITVAL_01=> "0x3007E3C00E201FE300FE001E007D0001F011FFC1002013FE033FDFF3FE0707DF00FFE10026118380",
INITVAL_00=> "0x000363C00600CC120202002010000000000200FE000003E00E000003F00600C003C21F0FC00003FD",
CSDECODE_B=> "0b011", CSDECODE_A=> "0b011", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -569,38 +569,38 @@ begin
gram0_4_0_2: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000003C40101E013FE0F003E1001F03FC003F8FE001C01FE013E303003F13FE0E3E0FE001E0",
INITVAL_1E=> "0x0011E03C0E3E1FE005E01FE01003FF3FE0F3FFFF20FFF3FE3F00000000000001C078F02000E1E000",
INITVAL_1D=> "0x1C00000000003C10061F3C10001D002060F3020F01C002001F3C0001C1F801E000001D1E00000000",
INITVAL_1C=> "0x3FDFE0FDF03FE7F3E3FF07E010020100000001801E2010F0000020101E010003C0001E03D0001CF0",
INITVAL_1B=> "0x2007E0E00000CE00020103C0001C003FAF3002000390001C00001E03FDFE3E3FF3FD823FFFF00201",
INITVAL_1A=> "0x0000000000301FE00D800021E000F0000003800201DE0000701E0003E10E0023D0000E001E0000E0",
INITVAL_19=> "0x201CE27006001E0000F000000001FE3FF073FFFF307FF3FE1F0000000000000003FC7E380023C000",
INITVAL_18=> "0x1E00000000004F10020F0F10000D8031E073800101C000001E1E0001E18E00F003FC1F3E0FE00000",
INITVAL_17=> "0x3FDFE0FDF13FE3F3F3FF03E010020100000001F00FE0103A010030100E000001C2000E01D8000478",
INITVAL_16=> "0x301E607000000F10020103D0001D0031E7F003F901E013FE3F001F03FDFE3F3FE3FD823FFFF00201",
INITVAL_15=> "0x00000000000F180005C02000E00070000003C00000CF0000390F0000719C0021E2000E000E000070",
INITVAL_14=> "0x2007E3F0023F0FE0018007E01203FF3FF833FFFF383FF3FE0F00000000000018000438380001E000",
INITVAL_13=> "0x0F00000000002712020F07180005803FA023C00000C002000F0E0003F102006012020F0018000400",
INITVAL_12=> "0x3FDFE07DF93FE1F3FBFF01E0100201000000003C07800039800038100C002000E3000600D8000439",
INITVAL_11=> "0x3818207C00002790020100D8000F812023F0020101C0000039001F83FDFE3F3FE3FDC03FEFF00201",
INITVAL_10=> "0x0000000000079C0005C03820200038000000F80000C700027907800039F80003C3C0020003C00078",
INITVAL_0F=> "0x3001E3E002000700000007800301FE3FFC13FFFF383FF3FE0F0000000000001803FC1E301FE03C00",
INITVAL_0E=> "0x3FE0F3C3FF00238300063F1FE005C03E000381FE003E13FE01070001F100003E13FE073F1FE00000",
INITVAL_0D=> "0x3FDFE03FFD3FE0F3FFFF00E010020100000001F003E013E2FF201FE1FC001FE013020300C003FE1F",
INITVAL_0C=> "0x3810003C003FC06203FF003C1007C02021F001FE00F813FE0F001F83FDFE3F9FE1FDE03FE7F00201",
INITVAL_0B=> "0x0000000000300FE0000001C013C3FF003FD00000000300030103E0101AC1001C001C001FC0000018",
INITVAL_0A=> "0x300021C0003FC3E001F800201383FE3FFC13FFFF3C3FF3FE06000000000000000000000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x3FDFF01FFF3FE0F3FFFF00E010020100000000000000000000000000000000000000000000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000001FC3FCFE3FDFE0FDF03FE3F00201",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x0000000000000000000000000381FE1FFE13FFFF3E3FF3FC02000000000000000000000000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x3FDFF01FFF3FF073FFFF006010020100000000000000000000000000000000000000000000000000",
INITVAL_02=> "0x00000000000000000000000000000000000000000000000000001FC3FC7E3FDFE07DF03FE3F00201",
INITVAL_1F=> "0x000002007E200060C0003F00000030180000E000000013820F30006060000020F302000001C20006",
INITVAL_1E=> "0x3E0060000000C003000200180005C001A012301E380000000000000000003FC010C201003F10FC00",
INITVAL_1D=> "0x06000039000023C0018007E010F3010021E1C000000003020100DC03FC010006000000004000021D",
INITVAL_1C=> "0x3E0C0001800F8000700000000000000000E0780000207303060030100780300023C0023818200D80",
INITVAL_1B=> "0x202033C2000021900200004302020F0040100207000380000001D8000C0C3010003D000020100000",
INITVAL_1A=> "0x000000E1800021C0C0000001D0023130002030000060101CE13001C060000060F300010003030002",
INITVAL_19=> "0x004700000100C0030002000700001E03800031C00020E00000000000010020206300000021D30002",
INITVAL_18=> "0x06000061C000076000E03800037100002761C0000000020207000300020F00060000000040030203",
INITVAL_17=> "0x01DC03FDFF200061800000000000002000200000004061820100500007013FE010E2070C00003980",
INITVAL_16=> "0x206020C20700219002003FC1E2000301C0000006000380000000039003FD3FE013C2010000100201",
INITVAL_15=> "0x000000E000000700C0000023100230201FE01D0001F0000D80300320600001E0F30000001E03FC00",
INITVAL_14=> "0x004C00000100C00300020000C3800000000000000043900201000000000000201203FE0020F20006",
INITVAL_13=> "0x060000C0E0200C2000703000207106003C61C000000000020F001F100E0C3C07E001FE006011C201",
INITVAL_12=> "0x002010020000070200060000000000000FC000003FC070C20100D00004000C2010720C0600006180",
INITVAL_11=> "0x21E020C01800219002000180E2007E019803FC063FC3E0010020207380060003E0000E00C0000000",
INITVAL_10=> "0x000002007E0000E0C00000261000300000C00D800390000500302C2060000720F30000000C00C000",
INITVAL_0F=> "0x000C00003C00C0030002200020710003E013F20F038E00000000000000003F0000C0000020F20006",
INITVAL_0E=> "0x060001807038180000703000207118003061C400000000021D002010000C038600000000400033C1",
INITVAL_0D=> "0x3018000CE0039800041C00000000000000003900002071C00000500004010600101A390E00003180",
INITVAL_0C=> "0x272020C06000219002002300600000018C00000600038001C01C000010E00E180000300300000000",
INITVAL_0B=> "0x0000000180202060C000002390023000198004C00710000DC030102064001C20F300000018006000",
INITVAL_0A=> "0x000E00000C00C00300021800000CC0301C0000100E180004000000000000300020E0000021D30002",
INITVAL_09=> "0x06000300181C100004E03800007170002061D8000000000331002600000E01860000000040001E31",
INITVAL_08=> "0x180000600E0600001C3000000000000000607100002073800000101006010340000E711C00001D80",
INITVAL_07=> "0x3C2020C1800001900200360002000600DC0000070003800060070000080000F01006C10E00000000",
INITVAL_06=> "0x000001C1C00000E0C00000C0E00231001F0000700C0000787030002078003020F300000010003C00",
INITVAL_05=> "0x03C380003C00C00300020E180000400003C000303800000C0000000000001FC01383FF003F10FC00",
INITVAL_04=> "0x3FC1F2020F0E00001D8007E01073C1002061E00000000003E1001C03FC003F07E001FE007010061D",
INITVAL_03=> "0x080003800006000030600000000000001F800C003FC06003FD001FC3FC0001D00004E0000FE00180",
INITVAL_02=> "0x302020C10000219002001C000001F0002013FC063FC3E00030018000080000701007011820000000",
INITVAL_01=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000070600004020066000302000201800000000000000000000000000000000",
CSDECODE_B=> "0b100", CSDECODE_A=> "0b100", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -635,37 +635,37 @@ begin
gram0_5_0_1: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x0000000000000000000000000000000000000000000000000000000001FC3FE01002010000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x0000000000000000000000000000003F9FE03C000000000000000000000000000000000000000000",
INITVAL_1B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x001C0001800000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000C30000000000000000000",
INITVAL_18=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000001800030000000000000000000000000000000000000000000",
INITVAL_16=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_15=> "0x000C0001800000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000C30000000000000000000",
INITVAL_13=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_12=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_12=> "0x00000000000000000000000000000001C000F0010000000000000000000000000000000000000000",
INITVAL_11=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_10=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_10=> "0x000FE0018000E0100201000000000000000000000000000000000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000003F80C301FE000000000000000",
INITVAL_0E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0D=> "0x0000000000000000000000000001F001A00030FC0000000000000000000000000000000000000000",
INITVAL_0C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x0F8C0001803C00200000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000001F00000C300001F0000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000003800601800030000020100201000000000000000000000000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x002C1003810007800000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000300060000C300002000E0000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x0000000000000000000000000000000000000000000000000000000000000000001CE0001E003C00",
INITVAL_02=> "0x38000001FE000003F802001FC01C000020F003E0003011FE0038000381C001D003FC3E001FE01C00",
INITVAL_01=> "0x3F1FE0FDC03FE3F3C3FF03E010020100000381E01C000381FE0020103C003FC0E001F101E013F3FF",
INITVAL_00=> "0x0001E1C0003F87E001F800E0103A013C2E1003F907E013FAFF001C03FDFE3C3FF3FF063FFFF00601",
INITVAL_03=> "0x00000000000000000000000000780001800070000380000000000000000000000000000000000000",
INITVAL_02=> "0x000000000000000000000000000000000000000000000000000000000000000000000000000000E0",
INITVAL_01=> "0x000F8001800038100E01000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x000000000000000000000000000000000000000000000000000E0003E00E3007E000F00000000000",
CSDECODE_B=> "0b101", CSDECODE_A=> "0b101", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,

View File

@ -3,7 +3,7 @@ Starting process: Module
Starting process:
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun Apr 22 17:34:06 2018
Sun May 10 13:18:44 2020
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -13,7 +13,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
BEGIN SCUBA Module Synthesis
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -21,7 +21,7 @@ BEGIN SCUBA Module Synthesis
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,6 +1,6 @@
-- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.10.0.111.2
-- Module Version: 7.5
-- Sun Apr 22 17:34:06 2018
-- Sun May 10 13:18:44 2020
-- parameterized module component declaration
component gram0

View File

@ -1,5 +1,5 @@
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun Apr 22 17:34:06 2018
Sun May 10 13:18:44 2020
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -9,7 +9,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
BEGIN SCUBA Module Synthesis
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -17,7 +17,7 @@ BEGIN SCUBA Module Synthesis
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,12 +1,12 @@
obj-m := lmg6202ulyt.o
KDIR := ~/projects/arm-linux/current
KDIR := ~/projects/linux/opi-current
PWD := $(shell pwd)
default: lmg6202ulyt.ko
lmg6202ulyt.ko: lmg6202ulyt.c
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
$(MAKE) -C $(KDIR) M=$(PWD)
deploy: lmg6202ulyt.ko
scp $< markus@opi:/home/markus/lmg6202ulyt/deploy
scp $< markus@opi:/home/markus/projects/lw35/deploy/
clean:
rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers

View File

@ -8,8 +8,7 @@
#include <linux/gpio/consumer.h>
#include <linux/fb.h>
#define BPP 8 // 8
#define PIX_THRESHOLD 0
#define BPP 16
#define LMGE_GPIO 100
#define LMGE_OTHER 99
@ -21,9 +20,9 @@ MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("lmg6202ulyt display driver");
MODULE_VERSION("0.1");
static char *testparam = "param";
module_param(testparam, charp, S_IRUGO);
MODULE_PARM_DESC(testparam, "A test parameter");
static int pix_threshold = 0;
module_param(pix_threshold, int, 0);
MODULE_PARM_DESC(pix_threshold, "Black / White threshold. 0-255");
static struct of_device_id lmg6202ulyt_dt_ids[] = {
{ .compatible = "hitachi,lmg6202ulyt", },
@ -122,7 +121,9 @@ static int lmg6202ulyt_init_fix(struct lmg6202ulyt_priv *priv)
else
fix->visual = FB_VISUAL_TRUECOLOR;
printk(KERN_INFO "lmg6202ulyt: Using %d bpp.\n", var->bits_per_pixel);
printk(KERN_INFO "lmg6202ulyt: Using %d bpp (%s).\n",
var->bits_per_pixel,
(var->grayscale ? "grayscale" : "truecolor"));
return 0;
}
@ -209,6 +210,7 @@ void lmg6202ulyt_deferred_io(struct fb_info *info, struct list_head *pagelist)
int i;
int blk;
char __iomem *pixel;
char pixval;
int txsz;
spi_write(priv->spi, buf, 5);
@ -219,7 +221,13 @@ void lmg6202ulyt_deferred_io(struct fb_info *info, struct list_head *pagelist)
buf[0] = 1;
for (i = 0; i < BLOCKSIZE * 8; i++) {
if (*pixel > PIX_THRESHOLD) {
#if BPP == 8
pixval = *(pixel);
#else
pixval = *(pixel + 1);
// TODO: We should have more cases here for higher BPPs
#endif
if (pixval > pix_threshold) {
buf[(i / 8) + 1] |= (1 << (7 - (i % 8)));
}
if (pixel >= info->screen_base + info->screen_size - ((info->var.bits_per_pixel) / 8))

View File

@ -1,3 +1,2 @@
*.raw
*.mem
*.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

12
doc/ioc.md 100644
View File

@ -0,0 +1,12 @@
# IOC
## Firmware
### General
* All serial links run at 19200 baud
### Bootloader
* The bootloader is a standard Arduino bootloader with the following additions
* Use ASCII command 'X' to enable byass mode. Everything received on UART RX will be forwarded to UART TX until the next reset.
* Use ASCII command 'Y' to set the next unit in the chain into bypass mode.
* Use ASCII command 'Z' to immediately launch into the user firmware
* Use the following avrdude command to program: `avrdude -p m8 -P /dev/ttyUSBx -c arduino -b 19200 -U flash:w:$(TARGET).hex`

8
ioc/avr-bootloader/.gitignore vendored 100644
View File

@ -0,0 +1,8 @@
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin

View File

@ -0,0 +1,440 @@
/**********************************************************/
/* Serial Bootloader for Atmel mega8 AVR Controller */
/* */
/* ATmegaBOOT.c */
/* */
/* Copyright (c) 2003, Jason P. Kyle */
/* */
/* Hacked by DojoCorp - ZGZ - MMX - IVR */
/* Hacked by David A. Mellis */
/* Hacked by Markus Koch */
/* */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will */
/* be useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with this program; if not, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/* Target = Atmel AVR m8 */
/**********************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define MAX_TIME_COUNT (F_CPU>>4)
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x12
// AVR-GCC compiler compatibility
// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
// if necessary, convert outb and inb to outp and inp
#ifndef outb
#define outb(sfr,val) (_SFR_BYTE(sfr) = (val))
#endif
#ifndef inb
#define inb(sfr) _SFR_BYTE(sfr)
#endif
/* defines for future compatibility */
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
#define eeprom_rb(addr) eeprom_read_byte ((uint8_t *)(addr))
#define eeprom_rw(addr) eeprom_read_word ((uint16_t *)(addr))
#define eeprom_wb(addr, val) eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#define SIG2 0x93
#define SIG3 0x07
#define PAGE_SIZE 0x20U //32 words
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
union address_union {
uint16_t word;
uint8_t byte[2];
} address;
union length_union {
uint16_t word;
uint8_t byte[2];
} length;
struct flags_struct {
unsigned eeprom : 1;
unsigned rampz : 1;
} flags;
uint8_t buff[256];
//uint8_t address_high;
uint8_t pagesz=0x80;
uint8_t i;
//uint8_t bootuart0=0,bootuart1=0;
void (*app_start)(void) = 0x0000;
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
/* Disable interrupts */
cli();
/* Pre-init I/O */
DDRB = 0;
DDRC = 0;
DDRD = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
asm volatile("nop\n\t");
/* initialize UART(s) depending on CPU defined */
/* m8 */
UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate
UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1
/*for (i = 0; i < 16; i++) {
_delay_loop_2(0);
}*/
/* forever */
for (;;) {
//if ((inb(UCSRA) & _BV(RXC))){
/* get character from UART */
ch = getch();
/* A bunch of if...else if... gives smaller code than switch...case ! */
/* Hello is anyone home ? */
if (ch == '0') {
nothing_response();
}
/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else if (ch == '1') {
if (getch() == ' ') {
putch(0x14);
putch('A');
putch('V');
putch('R');
putch(' ');
putch('I');
putch('S');
putch('P');
putch(0x10);
}
}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else if (ch == '@') {
ch2 = getch();
if (ch2>0x85) getch();
nothing_response();
}
/* AVR ISP/STK500 board requests */
else if (ch == 'A') {
ch2 = getch();
if (ch2==0x80) byte_response(HW_VER); // Hardware version
else if (ch2==0x81) byte_response(SW_MAJOR); // Software major version
else if (ch2==0x82) byte_response(SW_MINOR); // Software minor version
//else if (ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
else byte_response(0x00); // Covers various unnecessary responses we don't care about
}
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
else if (ch == 'B') {
getNch(20);
nothing_response();
}
/* Parallel programming stuff DON'T CARE */
else if (ch == 'E') {
getNch(5);
nothing_response();
}
/* Enter programming mode */
else if (ch == 'P') {
nothing_response();
// FIXME: modified only here by DojoCorp, Mumbai, India, 20050626
//time_count=0; // exted the delay once entered prog.mode
}
/* Leave programming mode */
else if (ch == 'Q') {
nothing_response();
//time_count=MAX_TIME_COUNT_MORATORY; // once the programming is done,
// we should start the application
// but uisp has problems with this,
// therefore we just change the times
// and give the programmer 1 sec to react
}
/* Set to bypass until restart */
else if (ch == 'X') {
while (1) {
if (UCSRA & (1 << RXC)) {
UDR = UDR;
}
}
}
/* Send 'X' via UART TX (set next unit to bypass) */
else if (ch == 'Y') {
putch('X');
continue;
}
/* Start user code NOW */
else if (ch == 'Z') {
app_start();
}
/* Erase device, don't care as we will erase one page at a time anyway. */
else if (ch == 'R') {
nothing_response();
}
/* Set address, little endian. EEPROM in bytes, FLASH in words */
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
/* This might explain why little endian was used here, big endian used everywhere else. */
else if (ch == 'U') {
address.byte[0] = getch();
address.byte[1] = getch();
nothing_response();
}
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
else if (ch == 'V') {
getNch(4);
byte_response(0x00);
}
/* Write memory, length is big endian and is in bytes */
else if (ch == 'd') {
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E') flags.eeprom = 1;
for (w=0; w<length.word; w++) {
buff[w] = getch(); // Store data in buffer, can't keep up with serial data stream whilst programming pages
}
if (getch() == ' ') {
if (flags.eeprom) { //Write to EEPROM one byte at a time
for(w=0;w<length.word;w++) {
eeprom_wb(address.word,buff[w]);
address.word++;
}
} else { //Write to FLASH one page at a time
cli(); //Disable interrupts, just to be sure
while(bit_is_set(EECR,EEWE)); //Wait for previous EEPROM writes to complete
asm volatile(
"clr r17 \n\t" //page_word_count
"lds r30,address \n\t" //Address of FLASH location (in words)
"lds r31,address+1 \n\t"
"lsl r30 \n\t" //address * 2 -> byte location
"rol r31 \n\t"
"ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
"ldi r29,hi8(buff) \n\t"
"lds r24,length \n\t" //Length of data to be written (in bytes)
"lds r25,length+1 \n\t"
"sbrs r24,0 \n\t" //Even up an odd number of bytes
"rjmp length_loop \n\t"
"adiw r24,1 \n\t"
"length_loop: \n\t" //Main loop, repeat for number of words in block
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
"brne no_page_erase \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x03 \n\t" //Erase page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"no_page_erase: \n\t"
"ld r0,Y+ \n\t" //Write 2 bytes into page buffer
"ld r1,Y+ \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
"sts %0,r16 \n\t"
"spm \n\t"
"inc r17 \n\t" //page_word_count++
"cpi r17,%1 \n\t"
"brlo same_page \n\t" //Still same page in FLASH
"write_page: \n\t"
"clr r17 \n\t" //New page, write current one first
"rcall wait_spm \n\t"
"ldi r16,0x05 \n\t" //Write page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"same_page: \n\t"
"adiw r30,2 \n\t" //Next word in FLASH
"sbiw r24,2 \n\t" //length-2
"breq final_write \n\t" //Finished
"rjmp length_loop \n\t"
"wait_spm: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm \n\t"
"ret \n\t"
"final_write: \n\t"
"cpi r17,0 \n\t"
"breq block_done \n\t"
"adiw r24,2 \n\t" //length+2, fool above check on length after short page write
"rjmp write_page \n\t"
"block_done: \n\t"
"clr __zero_reg__ \n\t" //restore zero register
: "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31");
/* Should really add a wait for RWW section to be enabled, don't actually need it since we never */
/* exit the bootloader without a power cycle anyhow */
}
putch(0x14);
putch(0x10);
}
}
/* Read memory block mode, length is big endian. */
else if (ch == 't') {
length.byte[1] = getch();
length.byte[0] = getch();
if (getch() == 'E') flags.eeprom = 1;
else {
flags.eeprom = 0;
address.word = address.word << 1; // address * 2 -> byte location
}
if (getch() == ' ') { // Command terminator
putch(0x14);
for (w=0; w < length.word; w++) { // Can handle odd and even lengths okay
if (flags.eeprom) { // Byte access EEPROM read
putch(eeprom_rb(address.word));
address.word++;
} else {
if (!flags.rampz) putch(pgm_read_byte_near(address.word));
address.word++;
}
}
putch(0x10);
}
}
/* Get device signature bytes */
else if (ch == 'u') {
if (getch() == ' ') {
putch(0x14);
putch(SIG1);
putch(SIG2);
putch(SIG3);
putch(0x10);
}
}
/* Read oscillator calibration byte */
else if (ch == 'v') {
byte_response(0x00);
}
} /* end of forever loop */
}
void putch(char ch)
{
/* m8 */
while (!(inb(UCSRA) & _BV(UDRE)));
outb(UDR,ch);
}
char getch(void)
{
/* m8 */
uint32_t count = 0;
while(!(inb(UCSRA) & _BV(RXC))) {
/* HACKME:: here is a good place to count times*/
count++;
if (count > MAX_TIME_COUNT)
app_start();
}
return (inb(UDR));
}
void getNch(uint8_t count)
{
uint8_t i;
for(i=0;i<count;i++) {
getch(); // need to handle time out
}
}
void byte_response(uint8_t val)
{
if (getch() == ' ') {
putch(0x14);
putch(val);
putch(0x10);
}
}
void nothing_response(void)
{
if (getch() == ' ') {
putch(0x14);
putch(0x10);
}
}

View File

@ -4,3 +4,5 @@
modules.order
Module.symvers
*.pro.user
.*
*.a

View File

@ -1,12 +1,12 @@
obj-m := lw35-ioc.o
KDIR := ~/projects/arm-linux/current
obj-m := lw35ioc.o
KDIR := ~/projects/linux/opi-current
PWD := $(shell pwd)
default: lw35-ioc.ko
lw35-ioc.ko: lw35-ioc.c
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
default: lw35ioc.ko
lw35ioc.ko: lw35ioc.c
$(MAKE) -C $(KDIR) M=$(PWD)
deploy: lw35-ioc.ko
scp $< markus@opi:/home/markus/lw35-ioc/deploy
deploy: lw35ioc.ko
scp $< markus@opi:/home/markus/projects/lw35/deploy/
clean:
rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers

View File

@ -1,28 +0,0 @@
/*
Reading: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
*/
&spi1 {
status = "okay";
lw35ioc@0 {
compatible = "brother,lw35ioc";
reg = <0x0>;
spi-max-frequency = <2000000>;
pinctrl-names = "default";
pinctrl-0 = <&lw35ioc>;
data-gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* TODO: get real IO num */
interrupt-parent = <&pio>;
interrupts = <52 2>;
};
};
&pio {
lmg6202ulyt_opc: lmg6202ulyt_pins {
pins = "PA7";
function = "gpio_out";
interrupt-controller;
#interrupt-cells = <1>;
};
};

View File

@ -0,0 +1,41 @@
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index c8201e79dff3..5407742acad6 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -210,12 +210,22 @@ &uart0 {
status = "okay";
};
+&pio {
+ lw35ioc_pins: lw35ioc-pins {
+ pins = "PA10";
+ function = "gpio_out";
+ };
+};
+
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1_pins>;
lw35ioc@0 {
compatible = "brother,lw35";
+ pinctrl-names = "default";
+ pinctrl-0 = <&lw35ioc_pins>;
+ rst-gpios = <&pio 0 10 GPIO_ACTIVE_LOW>;
};
};
@@ -242,3 +252,13 @@ &usbphy {
/* VBUS on USB host ports are always on */
status = "okay";
};
+
+&spi0 {
+ status = "okay";
+ lmg6202ulyt@0 {
+ compatible = "hitachi,lmg6202ulyt";
+ reg = <0x0>;
+ spi-max-frequency = <2000000>;
+ cs-gpios = <0>, <&pio 0 3 GPIO_ACTIVE_LOW>;
+ };
+};

View File

@ -1,78 +0,0 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
/*
* irq in general: https://notes.shichao.io/lkd/ch7/
* raspi irqs: http://morethanuser.blogspot.com/2013/04/raspberry-pi-gpio-interrupts-in-kernel.html
* kdoc devtree irq: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
* GPIOD doc (including irq): https://www.kernel.org/doc/Documentation/gpio/consumer.txt
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("LW35 I/O Controller Driver");
MODULE_VERSION("0.1");
static char *testparam = "param";
module_param(testparam, charp, S_IRUGO);
MODULE_PARM_DESC(testparam, "A test parameter");
static struct of_device_id lw35ioc_dt_ids[] = {
{ .compatible = "brother,lw35", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids);
struct lw35ioc_priv {
struct spi_device *spi;
// USER VARS HERE
};
static int lw35ioc_probe(struct spi_device *spi)
{
struct lw35ioc_priv *priv = NULL;
printk(KERN_INFO "lw35ioc: probe\n");
priv = devm_kzalloc(&spi->dev,
sizeof(struct lw35ioc_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
spi_set_drvdata(spi, priv);
priv->spi = spi;
printk(KERN_INFO "lw35ioc: Loaded driver\n");
return 0;
// Error handlers go here
}
static int lw35ioc_remove(struct spi_device *spi)
{
struct lw35ioc_priv *priv = spi_get_drvdata(spi);
return 0;
}
static struct spi_driver lw35ioc_driver = {
.probe = lw35ioc_probe,
.remove = lw35ioc_remove,
.driver = {
.name = "lw35ioc",
.owner = THIS_MODULE,
.of_match_table = lw35ioc_dt_ids,
},
};
module_spi_driver(lw35ioc_driver);

View File

@ -0,0 +1,744 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/serdev.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/circ_buf.h>
// #define ENABLE_DEBUG ENABLE_DEBUG
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("LW-35 I/O Controller Driver");
MODULE_VERSION("0.1");
static int debug_level = 0;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "Debug level");
/* Only for chrdev... man they really suck! */
static struct serdev_device *static_serdev = NULL;
static DECLARE_WAIT_QUEUE_HEAD(wq);
void pbuf_work_handler(struct work_struct *work);
DECLARE_WORK(pbuf_work, pbuf_work_handler);
static DEFINE_SPINLOCK(printer_status_lock);
static struct of_device_id lw35ioc_dt_ids[] = {
{ .compatible = "brother,lw35", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids);
/* Chardev */
#define DEVICE_NAME "lw35"
#define CLASS_NAME "lw35ioc"
/* Only used for initialization, not for actual keycode mapping */
static int keycode_map[] = {
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
KEY_F10, KEY_F11, KEY_F12,
KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, KEY_PAGEUP, KEY_PAGEDOWN,
KEY_102ND, KEY_INSERT, KEY_HOME, KEY_END, KEY_PRINT,
KEY_CAPSLOCK, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_TAB,
KEY_MINUS, KEY_COMMA, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE,
KEY_GRAVE, KEY_SPACE, KEY_EQUAL, KEY_DOT, KEY_SLASH, KEY_APOSTROPHE,
KEY_BACKSLASH,
KEY_DELETE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE,
KEY_SYSRQ
};
enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
enum lw35ioc_packet_state {SYNC, TYPE, KEYBOARD, PRINTER};
struct lw35ioc_packet {
enum lw35ioc_packet_state state;
int payload_offset;
};
struct lw35ioc_chardev {
int major_number;
struct class* class;
struct device* device;
int open_count;
};
struct lw35ioc_printer_status{
int buffer_free;
int status;
int rx_count;
int reserved1;
};
#define UART_BUF_SIZE 256
#define PBUF_SIZE 256
struct lw35ioc_priv {
struct serdev_device *serdev;
struct input_dev *input_dev;
struct gpio_desc *gpio_rst; /* GPIO to reset both AVRs */
struct lw35ioc_chardev chardev;
struct lw35ioc_printer_status printer_status_temp;
struct lw35ioc_printer_status printer_status;
char uart_buf_rx[UART_BUF_SIZE];
char *uart_buf_rx_rd;
char *uart_buf_rx_wr;
char pbuf[PBUF_SIZE];
unsigned long pbuf_tail;
unsigned long pbuf_head;
enum lw35ioc_state state;
struct lw35ioc_packet packet;
u8 tx_count;
u8 tx_count_resync;
};
static int lw35ioc_process_buf(struct serdev_device *serdev,
const unsigned char *data,
size_t count)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned char c;
int ev;
int i;
unsigned long lock_flags;
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, "IRQ.\n");
#endif
for (i = 0; i < count; ++i) {
c = data[i];
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, " RX [%d]: %02x\n", priv->packet.state, c);
#endif
switch (priv->packet.state) {
case SYNC:
if (c == 0xFF)
priv->packet.state = TYPE;
break;
case TYPE:
if (c == 0x55)
priv->packet.state = KEYBOARD;
else if (c == 0xAA)
priv->packet.state = PRINTER;
else
priv->packet.state = SYNC;
priv->packet.payload_offset = 0;
break;
case KEYBOARD:
if (c > 127) {
c -= 128;
ev = 1;
} else {
ev = 0;
}
input_report_key(priv->input_dev, c, ev);
input_sync(priv->input_dev);
priv->packet.state = SYNC;
break;
case PRINTER:
switch (priv->packet.payload_offset) {
case 0: /* Status */
priv->printer_status_temp.status = (int)c;
break;
case 1: /* Buffer status */
priv->printer_status_temp.buffer_free = (int)c;
break;
case 2: /* Reserved */
priv->printer_status_temp.rx_count = (int)c;
break;
case 3: /* Reserved */
priv->printer_status_temp.reserved1 = (int)c;
dev_info(&serdev->dev,
"New printer status. status=0x%02X buffer_free=0x%02X rx_count=0x%02X reserved=0x%02X.\n",
priv->printer_status_temp.status,
priv->printer_status_temp.buffer_free,
priv->printer_status_temp.rx_count,
priv->printer_status_temp.reserved1);
if (priv->printer_status_temp.status == 0xFF) {
dev_err(&serdev->dev,
"HARDFAULT in printer firmware! Reset required.\n");
}
spin_lock_irqsave(&printer_status_lock, lock_flags);
memcpy(&priv->printer_status,
&priv->printer_status_temp,
sizeof(priv->printer_status));
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
if (priv->printer_status_temp.buffer_free > 0)
schedule_work(&pbuf_work);
priv->packet.state = SYNC;
break;
default:
break;
}
priv->packet.payload_offset++;
break;
}
}
return i;
}
static int lw35ioc_receive_buf(struct serdev_device *serdev,
const unsigned char *data,
size_t count)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
int i;
switch (priv->state) {
case ACTIVE:
return lw35ioc_process_buf(serdev, data, count);
break;
case PASSIVE:
break;
default:
/* Pass data directly to chardev */
for (i = 0; i < count; ++i) {
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, " RX [PSV]: %02x\n", data[i]);
#endif
*(priv->uart_buf_rx_wr) = data[i];
if (priv->uart_buf_rx_wr == priv->uart_buf_rx + UART_BUF_SIZE - 1)
priv->uart_buf_rx_wr = priv->uart_buf_rx;
else
priv->uart_buf_rx_wr++;
if (priv->uart_buf_rx_rd == priv->uart_buf_rx_wr) {
dev_err(&serdev->dev, "UART RX buffer overflow.\n");
}
}
wake_up_interruptible(&wq);
}
return count; /* Pretend we read all data */
}
static void lw35ioc_write_wakeup(struct serdev_device *serdev)
{
// schedule work here
}
static struct serdev_device_ops lw35ioc_serdev_ops = {
.receive_buf = lw35ioc_receive_buf,
.write_wakeup = lw35ioc_write_wakeup,
};
static void lw35ioc_set_hw_reset(struct serdev_device *serdev,
int reset_active)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
gpiod_set_value(priv->gpio_rst, !!reset_active);
}
static void lw35ioc_reset_ioc_hw(struct serdev_device *serdev)
{
dev_info(&serdev->dev, "Resetting IOC...\n");
lw35ioc_set_hw_reset(serdev, 1);
usleep_range(90000, 100000);
lw35ioc_set_hw_reset(serdev, 0);
usleep_range(90000, 100000);
}
/* Chardev */
static int lw35ioc_chardev_open(struct inode *inodep, struct file *filep) {
struct serdev_device *serdev = static_serdev;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
filep->private_data = serdev;
if (!priv->chardev.open_count) {
dev_info(&serdev->dev, "Opened chardev.\n");
switch (priv->state) {
case PROG_KBD:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "X", 1, 0);
dev_info(&serdev->dev, "Put ioc into programming mode: keyboard.\n");
break;
case PROG_PRI:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "Y", 1, 0);
dev_info(&serdev->dev, "Put ioc into programming mode: printer.\n");
break;
case BYPASS:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "XX", 2, 0);
dev_info(&serdev->dev, "Put ioc into bypass mode.\n");
break;
case INIT:
case PASSIVE:
// TODO: locks
priv->pbuf_tail = 0;
priv->pbuf_head = 0;
lw35ioc_reset_ioc_hw(serdev);
usleep_range(2100000, 2210000);
dev_info(&serdev->dev, "Put ioc into active mode.\n");
if (priv->state == INIT) {
serdev_device_write(serdev, "\xFF", 1, 0);
priv->state = ACTIVE;
}
break;
case ACTIVE:
/* Don't do anything when active */
break;
default:
break;
}
} else {
dev_err(&serdev->dev, "Rejected. Device may only be opened once.\n");
//return -EBUSY; // TODO
}
priv->tx_count_resync = 1;
priv->chardev.open_count++;
return 0;
}
static ssize_t lw35ioc_chardev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
int error_count;
int available;
available = priv->uart_buf_rx_wr - priv->uart_buf_rx_rd;
if (available < 0)
available = 1;
if (!available) { /* Wait for data to become available */
wait_event_interruptible(wq, priv->uart_buf_rx_rd != priv->uart_buf_rx_wr);
available = priv->uart_buf_rx_wr - priv->uart_buf_rx_rd;
if (available < 0)
available = 1; /* TODO: We should calculate the remaining block until wraparound here... */
if (!available)
return -EAGAIN;
}
if (available < len)
len = available;
error_count = copy_to_user(buffer, priv->uart_buf_rx_rd, len);
len -= error_count;
priv->uart_buf_rx_rd += len;
if (priv->uart_buf_rx_rd >= priv->uart_buf_rx + UART_BUF_SIZE) {
priv->uart_buf_rx_rd -= UART_BUF_SIZE;
}
if (error_count == 0) {
return len;
} else {
dev_err(&serdev->dev, "Failed to read %d characters to chardev.\n",
error_count);
return -EFAULT;
}
}
char msg[256]; // TODO
static ssize_t lw35ioc_chardev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) {
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned long tail;
int i;
int ret;
switch (priv->state) {
case ACTIVE:
/* Put data into pbuf */
// TODO: spinlock
if (CIRC_SPACE(priv->pbuf_head, READ_ONCE(priv->pbuf_tail), PBUF_SIZE) < 1) {
dev_err(&serdev->dev, "chdev write: Waiting for space...\n");
if (ret = (wait_event_interruptible(wq, CIRC_SPACE(priv->pbuf_head, priv->pbuf_tail, PBUF_SIZE) >= 1))) { // TODO: Accessing pbuf_tail without any protection... this might be bad?
dev_err(&serdev->dev,
"chdev write: device closed while waiting. ret: %d\n",
ret);
// TODO: This is not proper handling of this I guess...
return len;
}
dev_err(&serdev->dev, "chdev write: done waiting...\n");
}
tail = READ_ONCE(priv->pbuf_tail);
for (i = 0; i < len; ++i) { // TODO: Block copy would be faster...
if (CIRC_SPACE(priv->pbuf_head, tail, PBUF_SIZE) >= 1) {
ret = copy_from_user(priv->pbuf + priv->pbuf_head,
buffer + i,
1);
if (ret) {
dev_err(&serdev->dev, "chdev write: copy_from_user failed (%d).\n",
ret);
i = len - 1;
}
smp_store_release(&(priv->pbuf_head),
(priv->pbuf_head + 1) & (PBUF_SIZE - 1));
} else {
dev_warn(&serdev->dev, "chdev write: ring buffer full.\n");
break;
}
}
len = i;
schedule_work(&pbuf_work);
dev_info(&serdev->dev,
"Copied %d bytes to FIFO (FIFO free: %d)",
len, CIRC_SPACE(priv->pbuf_head, tail, PBUF_SIZE));
break;
case PASSIVE:
len = -EBUSY; // TODO: Can I do this?
break;
default: /* Pass-through */
if (len > 256) {
len = 256;
}
copy_from_user(msg, buffer, len); // TODO: Return value
serdev_device_write_buf(serdev, msg, len);
}
return len;
}
static int lw35ioc_chardev_release(struct inode *inodep, struct file *filep){
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
priv->chardev.open_count--;
dev_info(&serdev->dev, "Device successfully closed\n");
return 0;
}
#define IOCTL_SET_MODE 42
static long lw35ioc_chardev_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
switch (cmd) {
case IOCTL_SET_MODE:
if (arg >= STATE_COUNT || arg < 0) {
dev_err(&serdev->dev, "Invalid driver mode: %lu", arg);
return -1;
}
priv->state = arg;
dev_info(&serdev->dev, "Switched driver mode to: %lu. Will be applied with next open().\n", arg);
break;
default:
dev_info(&serdev->dev, "Ignoring IOCTL %u(%lu)\n", cmd, arg);
break;
}
return 0;
}
__poll_t poll(struct file *filep, struct poll_table_struct *ptab)
{
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
poll_wait(filep, &wq, ptab);
if (priv->uart_buf_rx_wr != priv->uart_buf_rx_rd)
return EPOLLIN | EPOLLRDNORM;
return 0;
}
#define PRINTER_READY_MASK (0b00011111)
int printer_ready_for_data(struct lw35ioc_printer_status printer_status)
{
return ((printer_status.status & PRINTER_READY_MASK) == PRINTER_READY_MASK);
}
void pbuf_work_handler(struct work_struct *work)
{
// TODO: get private data using container_of(): https://linux-kernel-labs.github.io/master/labs/deferred_work.html
struct serdev_device *serdev = static_serdev; // Not cool, but whatever...
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned long head;
unsigned long tail;
unsigned long lock_flags;
int bsize = 0;
int i;
int locked = 0;
while (1) {
// TODO: We are the only consumer, so we should be fine without a spinlock, right?
head = smp_load_acquire(&priv->pbuf_head);
tail = priv->pbuf_tail;
bsize = CIRC_CNT(head, tail, PBUF_SIZE);
//dev_info(&serdev->dev, "CIRC CNT=%d\n", bsize);
if (bsize == 0)
break;
spin_lock_irqsave(&printer_status_lock, lock_flags);
locked = 1;
if (!printer_ready_for_data(priv->printer_status)) {
dev_warn(&serdev->dev, "Cannot transmit data to device. Device is not ready.\n");
break;
}
if (priv->tx_count_resync) {
priv->tx_count = priv->printer_status.rx_count;
priv->tx_count_resync = 0;
}
if (priv->printer_status.rx_count != priv->tx_count) {
dev_info(&serdev->dev, "Not transmitting any data to device because rx is unconfirmed [tx=%d, rx=%d].\n",
priv->tx_count, priv->printer_status.rx_count);
break;
}
if (bsize > priv->printer_status.buffer_free)
bsize = priv->printer_status.buffer_free;
if (bsize > CIRC_CNT_TO_END(head, tail, PBUF_SIZE))
bsize = CIRC_CNT_TO_END(head, tail, PBUF_SIZE);
if (bsize > priv->printer_status.buffer_free - 20)
bsize = priv->printer_status.buffer_free - 20; // TODO: Bug workaround
dev_info(&serdev->dev, "TX %d of %d bytes [%d bytes free on device].\n",
bsize,
CIRC_CNT(head, tail, PBUF_SIZE),
priv->printer_status.buffer_free);
priv->printer_status.buffer_free-=bsize;
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
locked = 0;
if (bsize == 0) {
dev_warn(&serdev->dev, "Cannot transmit data to device. Device buffer is full.\n");
break;
}
priv->tx_count += bsize;
serdev_device_write_buf(serdev,
priv->pbuf + tail,
bsize);
#ifdef ENABLE_DEBUG
for (i=0; i<bsize; ++i) {
dev_info(&serdev->dev,
"UART TX: %c\n",
priv->pbuf[tail + i]);
}
#endif
smp_store_release(&priv->pbuf_tail,
(tail + bsize) & (PBUF_SIZE - 1));
}
if (locked)
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
wake_up_interruptible(&wq); // There's some space available in the FIFO now, so wake up chardev write
}
static struct file_operations fops =
{
.open = lw35ioc_chardev_open,
.read = lw35ioc_chardev_read,
.write = lw35ioc_chardev_write,
.release = lw35ioc_chardev_release,
.unlocked_ioctl = lw35ioc_chardev_ioctl,
.poll = poll,
};
static int lw35ioc_cdev_init(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
priv->chardev.open_count = 0;
// Try to dynamically allocate a major number for the device
priv->chardev.major_number = register_chrdev(0, DEVICE_NAME, &fops);
if (priv->chardev.major_number < 0) {
dev_err(&serdev->dev, "Failed to register a major number\n");
return priv->chardev.major_number;
}
dev_info(&serdev->dev, "Registered correctly with major number %d\n", priv->chardev.major_number);
// Register the device class
priv->chardev.class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(priv->chardev.class)) {
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_err(&serdev->dev, "Failed to register device class\n");
return PTR_ERR(priv->chardev.class);
}
dev_info(&serdev->dev, "Device class registered correctly\n");
// Register the device driver
priv->chardev.device = device_create(priv->chardev.class, NULL, MKDEV(priv->chardev.major_number, 0), NULL, DEVICE_NAME);
if (IS_ERR(priv->chardev.device)) {
class_destroy(priv->chardev.class);
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_err(&serdev->dev, "Failed to create the device\n");
return PTR_ERR(priv->chardev.device);
}
dev_info(&serdev->dev, "Device class created correctly\n");
return 0;
}
static int lw35ioc_probe(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = NULL;
int ret = 0;
int i;
u32 speed = 19200;
struct input_dev *input_dev;
printk(KERN_INFO "lw35ioc: probe\n");
if (static_serdev) {
printk(KERN_ERR "lw35ioc: Can only be loaded once.\n");
goto fail_multicheck;
}
/* Allocate memory */
priv = devm_kzalloc(&serdev->dev,
sizeof(struct lw35ioc_priv),
GFP_KERNEL);
if (!priv) {
printk(KERN_ERR "lw35ioc: Not enough memory.\n");
return -ENOMEM;
}
priv->state = ACTIVE; // TODO: This should be passive
priv->uart_buf_rx_rd = priv->uart_buf_rx;
priv->uart_buf_rx_wr = priv->uart_buf_rx;
priv->pbuf_tail = 0;
priv->pbuf_head = 0;
priv->printer_status.buffer_free = 0;
priv->printer_status.status = 0;
priv->tx_count = 0;
priv->tx_count_resync = 1;
priv->serdev = serdev;
static_serdev = serdev;
priv->packet.state = SYNC;
serdev_device_set_drvdata(serdev, priv);
/* Register input device */
input_dev = devm_input_allocate_device(&serdev->dev);
if (!input_dev) {
dev_err(&serdev->dev, "Unable to allocate input device.\n");
return -ENOMEM;
}
priv->input_dev = input_dev;
input_dev->name = "lw35ioc";
input_dev->phys = "lw35ioc/input1";
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REP, input_dev->evbit);
for (i = 0; i < ARRAY_SIZE(keycode_map); i++)
__set_bit(keycode_map[i], input_dev->keybit);
ret = input_register_device(input_dev);
if (ret) {
dev_err(&serdev->dev, "Unable to register input device.\n");
goto fail_input;
}
serdev_device_set_client_ops(serdev, &lw35ioc_serdev_ops);
ret = serdev_device_open(serdev);
if (ret) {
dev_err(&serdev->dev, "Unable to open device.\n");
goto fail_serdev;
}
speed = serdev_device_set_baudrate(serdev, speed);
dev_info(&serdev->dev, "Using baudrate: %u\n", speed);
/* Register GPIO */
priv->gpio_rst = gpiod_get_index(&serdev->dev,
"rst",
0,
GPIOD_OUT_HIGH);
/* Register character device */
ret = lw35ioc_cdev_init(serdev);
if (ret) {
dev_err(&serdev->dev, "Unable to initialize character device.\n");
goto fail_gpio;
}
if (IS_ERR(priv->gpio_rst)) {
dev_err(&serdev->dev, "Unable to get reset GPIO.\n");
ret = -ENODEV; /* TODO */
goto fail_gpio;
}
lw35ioc_reset_ioc_hw(serdev);
dev_info(&serdev->dev, "Loaded driver.\n");
return 0;
fail_gpio:
fail_serdev:
input_unregister_device(input_dev);
fail_input:
devm_kfree(&serdev->dev, input_dev);
fail_multicheck:
return ret;
}
static void lw35ioc_remove(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
dev_info(&serdev->dev, "remove\n");
dev_info(&serdev->dev, " cdev class: %p\n", priv->chardev.class);
device_destroy(priv->chardev.class, MKDEV(priv->chardev.major_number, 0));
dev_info(&serdev->dev, "unreg\n");
class_unregister(priv->chardev.class);
dev_info(&serdev->dev, "destroy: SKIP\n");
//class_destroy(priv->chardev.class);
dev_info(&serdev->dev, "unreg-dev\n");
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_info(&serdev->dev, " gpio rst: %p\n", priv->gpio_rst);
dev_info(&serdev->dev, " serdev: %p\n", priv->serdev);
dev_info(&serdev->dev, " input dev: %p\n", priv->input_dev);
lw35ioc_set_hw_reset(serdev, 1);
usleep_range(90000, 100000); // Make sure the reset actually happens
gpiod_put(priv->gpio_rst);
serdev_device_close(priv->serdev);
input_unregister_device(priv->input_dev);
dev_info(&serdev->dev, "done.\n");
return;
}
static struct serdev_device_driver lw35ioc_driver = {
.probe = lw35ioc_probe,
.remove = lw35ioc_remove,
.driver = {
.name = "lw35ioc",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(lw35ioc_dt_ids),
},
};
module_serdev_device_driver(lw35ioc_driver);

View File

@ -6,4 +6,4 @@ CONFIG -= qt
INCLUDEPATH += /home/markus/projects/arm-linux/current/include
SOURCES += \
lw35-ioc.c
lw35ioc.c

View File

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(lw35-tool LANGUAGES C)
add_executable(lw35-tool main.c)

View File

@ -0,0 +1,78 @@
#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <sys/stat.h>
#include <fcntl.h>
#define IOCTL_SET_MODE 42
enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
int f;
static void help(int argc, char *argv[])
{
fprintf(stderr,
"usage: %s <command>\n\n"
" command: set-mode <mode>\n"
" mode: passive, active, rfu-kbd, rfu-pri, bypass\n",
argv[0]);
}
static int set_mode(int argc, char *argv[])
{
int mode = -1;
if (argc < 3) {
help(argc, argv);
return 10;
}
if (!strcmp(argv[2], "passive"))
mode = PASSIVE;
else if (!strcmp(argv[2], "rfu-kbd"))
mode = PROG_KBD;
else if (!strcmp(argv[2], "rfu-pri"))
mode = PROG_PRI;
else if (!strcmp(argv[2], "bypass"))
mode = BYPASS;
else if (!strcmp(argv[2], "active"))
mode = ACTIVE;
else if (!strcmp(argv[2], "init"))
mode = INIT;
if (mode == -1) {
fprintf(stderr, "Error: Invalid mode.\n");
return 10;
}
ioctl(f, IOCTL_SET_MODE, mode);
return 0;
}
int main(int argc, char *argv[])
{
int ret;
if (argc < 2) {
help(argc, argv);
return 1;
}
f = open("/dev/lw35", O_RDWR);
if (f == -1) {
fprintf(stderr, "Error opening lw35ioc device.\n");
return 3;
}
if (!strcmp(argv[1], "set-mode")) {
ret = set_mode(argc, argv);
} else {
fprintf(stderr, "Unknown command.\n");
ret = 2;
}
close(f);
return ret;
}

View File

@ -0,0 +1,8 @@
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin

View File

@ -0,0 +1,88 @@
# Makefile for ATmegaBOOT
# E.Lins, 2004-10-14
# program name should not be changed...
PROGRAM = main
PRODUCT=atmega8
# enter the parameters for the UISP isp tool
ISPPARAMS = -dprog=stk500 -dserial=$(SERIAL) -dspeed=115200
#DIRAVR = /usr/local/avr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = $(DIRAVR)/include
DIRLIB = $(DIRAVR)/avr/lib
MCU_TARGET = atmega8
LDSECTION = --section-start=.text=0x1c00
FUSE_L = 0xdf
FUSE_H = 0xca
ISPFUSES = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H)
ISPFLASH = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v
OBJ = $(PROGRAM).o
OPTIMIZE = -Os -funsigned-char -funsigned-bitfields -fno-inline-small-functions
DEFS = -DF_CPU=8000000 -DBAUD_RATE=19200
LIBS =
CC = $(DIRAVRBIN)/avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -D$(PRODUCT) $(DEFS) -I$(DIRINC)
override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = $(DIRAVRBIN)/avr-objcopy
OBJDUMP = $(DIRAVRBIN)/avr-objdump
SIZE = $(DIRAVRBIN)/avr-size
all: $(PROGRAM).elf lst text asm size
isp: $(PROGRAM).hex
$(ISPFUSES)
$(ISPFLASH)
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.s
rm -rf *.o *.elf
rm -rf *.lst *.map
asm: $(PROGRAM).s
%.s: %.c
$(CC) -S $(CFLAGS) -g1 $^
lst: $(PROGRAM).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
size: $(PROGRAM).hex
$(SIZE) $^
# Rules for building the .text rom images
text: hex bin srec
hex: $(PROGRAM).hex
bin: $(PROGRAM).bin
srec: $(PROGRAM).srec
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@

View File

@ -0,0 +1 @@
../../ioc/avr-bootloader/main.c

View File

@ -1,8 +1,9 @@
MCU=atmega8
PDEV=/dev/ttyUSB1
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000
LDFLAGS=-Wl,-gc-sections -Wl,-relax
CC=avr-gcc
TARGET=main
TARGET=fw_keyboard
OBJECT_FILES=main.o
all: $(TARGET).hex
@ -16,9 +17,12 @@ clean:
%.obj: $(OBJECT_FILES)
$(CC) $(CFLAGS) $(OBJECT_FILES) $(LDFLAGS) -o $@
rfu: $(TARGET).hex
scp $< markus@opi:/home/markus/projects/lw35/deploy/
ssh root@opi 'lw35-tool set-mode rfu-kbd; avrdude -p atmega8 -P /dev/lw35 -c arduino -b 19200 -U flash:w:/home/markus/projects/lw35/deploy/$<'
program: $(TARGET).hex
avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex
#avrdude -p $(MCU) -P /dev/ttyUSB1 -c arduino -b 57600 -U flash:w:$(TARGET).hex
avrdude -p $(MCU) -P $(PDEV) -c arduino -b 19200 -U flash:w:$(TARGET).hex
fuse:
avrdude -p m8 -c usbasp -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m

View File

@ -7,3 +7,5 @@ INCLUDEPATH += /usr/avr/include
SOURCES += \
main.c
DEFINES += __AVR_ATmega8__

View File

@ -1,5 +1,6 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define MATRIX_X(t) t##B
#define MATRIX_Y1(t) t##C
@ -11,8 +12,9 @@
#define DELAY_ROW_SWITCH() _delay_ms(1) //_delay_us(1)
#define BAUDRATE 9600
#define UBRR 51 // (F_CPU / BAUDRATE) / 32
#define BAUDRATE 19200
#define PRINTER_PACKET_SIZE 6
/* Keycode from include/linux/input.h */
#define KEY_RESERVED 0
@ -147,30 +149,46 @@
#define KEY_COMPOSE 127
#define SKEY_FN 255
#define KEYCODE_FN 127
// #define KEYCODE_FN 127
/*
* Special keys:
* * Control : Code
* * Alt : Del
* * FN : Delword
* * Del : Inhalt
* * ` : SM
* * Escape : Storno
* * Print : Menu
* * Pause : GS End
*
* FN Keymap:
* * F-Keys : Number keys for F1-F10, and ? and ` for F11-F12
* * Home / End / PGUP / PGDN : Arrow keys
* * Sys rq : Print
*/
static uint8_t keycode_translation_matrix[2][9][8] = {
{ /* Standard keymap */
{KEY_4, KEY_3, 3, 4, 5, 6, 7, 8},
{KEY_5, KEY_6, 13, 14, 15, 16, 17, 18},
{KEY_8, KEY_7, 23, 24, 25, 26, 27, 28},
{KEY_1, KEY_2, 33, 34, 35, 36, 37, 38},
{KEY_9, 42, 43, 44, 45, 46, 47, 48},
{51, KEY_0, 53, 54, 55, 56, 57, 58},
{61, 62, 63, 64, 65, 66, 67, 68},
{71, 72, 73, 74, 75, SKEY_FN, 77, 78},
{81, 82, 83, 84, 85, 86, 87, 88}
{KEY_5, KEY_6, KEY_R, KEY_T, KEY_C, KEY_F, KEY_UP, 0},
{KEY_8, KEY_7, KEY_Y, KEY_H, KEY_G, KEY_V, KEY_PAUSE, 0},
{KEY_1, KEY_2, KEY_Q, KEY_Z, KEY_A, KEY_S, KEY_CAPSLOCK, 0},
{KEY_9, KEY_J, KEY_I, KEY_U, KEY_B, KEY_N, KEY_RIGHT, 0},
{KEY_MINUS, KEY_0, KEY_P, KEY_O, KEY_M, KEY_COMMA, KEY_SYSRQ, 0},
{KEY_DELETE, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE, KEY_LEFT, KEY_DOWN, 0, KEY_LEFTCTRL},
{KEY_4, KEY_3, KEY_W, KEY_E, KEY_D, KEY_X, KEY_TAB, 0},
{KEY_GRAVE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE, KEY_LEFTALT, SKEY_FN, KEY_LEFTSHIFT, KEY_SPACE},
{KEY_EQUAL, KEY_L, KEY_BACKSLASH, KEY_K, KEY_DOT, KEY_SLASH, 0, KEY_APOSTROPHE}
},
{ /* FN keymap */
{ 1, 2, 3, 4, 5, 6, 7, 8},
{11, 12, 13, 14, 15, 16, 17, 18},
{21, 22, 23, 24, 25, 26, 27, 28},
{31, 32, 33, 34, 35, 36, 37, 38},
{41, 42, 43, 44, 45, 46, 47, 48},
{51, 52, 53, 54, 55, 56, 57, 58},
{61, 62, 63, 64, 65, 66, 67, 68},
{71, 72, 73, 74, 75, SKEY_FN, 77, 78},
{81, 82, 83, 84, 85, 86, 87, 88}
{KEY_F5, KEY_F6, KEY_R, KEY_T, KEY_C, KEY_F, KEY_PAGEUP, 0},
{KEY_F8, KEY_F7, KEY_Z, KEY_H, KEY_G, KEY_V, KEY_PAUSE, 0},
{KEY_F1, KEY_F2, KEY_Q, KEY_102ND, KEY_A, KEY_S, KEY_CAPSLOCK, 0},
{KEY_F9, KEY_J, KEY_I, KEY_U, KEY_B, KEY_N, KEY_END, 0},
{KEY_F11, KEY_F10, KEY_P, KEY_O, KEY_M, KEY_COMMA, KEY_SYSRQ, 0},
{KEY_DELETE, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE, KEY_HOME, KEY_PAGEDOWN, 0, KEY_LEFTCTRL},
{KEY_F4, KEY_F3, KEY_W, KEY_E, KEY_D, KEY_X, KEY_TAB, 0},
{KEY_GRAVE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE, KEY_LEFTALT, SKEY_FN, KEY_LEFTSHIFT, KEY_SPACE},
{KEY_F12, KEY_L, KEY_BACKSLASH, KEY_K, KEY_DOT, KEY_SLASH, 0, KEY_APOSTROPHE}
}
};
@ -178,26 +196,81 @@ uint8_t matrix_state_last_vector[9] = {0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF};
uint8_t fn_active = 0;
/* UART forwarding */
#define RING_BUFFER_SIZE 256 // Important: must be 256 atm, when changed, you need to change code handling print_buffer_*.
volatile char ring_buffer[RING_BUFFER_SIZE];
volatile uint8_t ring_buffer_wr = 0;
volatile uint8_t ring_buffer_rd = 0;
#define UART_BYTE_READY (UCSRA & (1 << RXC))
void uart_putc(char c)
{
while (!(UCSRA & (1 << UDRE)));
UDR = c;
}
ISR(USART_RXC_vect)
{
if (UCSRA & (1 << RXC)) {
ring_buffer[ring_buffer_wr] = UDR;
ring_buffer_wr++; // WARNING: No overflow protection
// Will auto wrap at 256; print_buffer_wr = print_buffer_wr % PRINT_BUFFER_SIZE;
}
}
void uart_forward_packets()
{
uint8_t size;
uint8_t i;
if (ring_buffer_wr > ring_buffer_rd)
size = ring_buffer_wr - ring_buffer_rd;
else
size = ring_buffer_rd - ring_buffer_wr;
if (size >= PRINTER_PACKET_SIZE) {
/* check sync */
if (ring_buffer[ring_buffer_rd] != ((char)0xFF)) {
ring_buffer_rd++; /* Drop wrong sync header */
return;
}
if (ring_buffer[ring_buffer_rd + 1] != ((char)0xAA)) {
ring_buffer_rd += 1; /* Drop wrong app header */
return;
}
for (i = 0; i < PRINTER_PACKET_SIZE; ++i) {
uart_putc(ring_buffer[ring_buffer_rd]); // Will auto wrap at 256
ring_buffer_rd++;
}
}
}
void process_key_event(uint8_t col, uint8_t row, uint8_t state)
{
char c;
uint8_t keycode;
int event = 0;
keycode = keycode_translation_matrix[fn_active][col][row];
if (keycode == SKEY_FN) {
fn_active = state;
#ifdef KEYCODE_FN
while (!(UCSRA & (1 << UDRE)));
UDR = KEYCODE_FN | (state << 7);
c = KEYCODE_FN | (state << 7);
event = 1;
#endif
} else {
c = keycode | (state << 7);
while (!(UCSRA & (1 << UDRE)));
UDR = c;
event = 1;
}
if (event) {
uart_putc(0xFF);
uart_putc(0x55);
uart_putc(c);
}
}
@ -242,16 +315,23 @@ int main()
MATRIX_Y2(DDR) &= ~MASK_Y2; /* Disable rows */
MATRIX_Y1(PORT) &= ~MASK_Y1; /* Pull row low when selected */
MATRIX_Y2(PORT) &= ~MASK_Y2; /* Pull row low when selected */
UCSRB = (1 << TXEN);
UBRRH = (UBRR >> 8) & 0xFF;
UBRRL = UBRR & 0xFF;
/* Set up UART */
UCSRA = 0;
UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
UCSRC = 0;
UBRRH = ((((F_CPU / BAUDRATE) / 16) - 1) >> 8);
UBRRL = (((F_CPU / BAUDRATE) / 16) - 1);
fn_active = 0;
sei();
/* Continuously scan matrix */
while (1) {
for (col = 0; col < 9; ++col) {
matrix_scan_col(col);
}
uart_forward_packets();
}
}

View File

@ -0,0 +1,88 @@
# Makefile for ATmegaBOOT
# E.Lins, 2004-10-14
# program name should not be changed...
PROGRAM = main
PRODUCT=atmega8
# enter the parameters for the UISP isp tool
ISPPARAMS = -dprog=stk500 -dserial=$(SERIAL) -dspeed=115200
#DIRAVR = /usr/local/avr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = $(DIRAVR)/include
DIRLIB = $(DIRAVR)/avr/lib
MCU_TARGET = atmega8
LDSECTION = --section-start=.text=0x1c00
FUSE_L = 0xdf
FUSE_H = 0xca
ISPFUSES = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H)
ISPFLASH = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v
OBJ = $(PROGRAM).o
OPTIMIZE = -Os -funsigned-char -funsigned-bitfields -fno-inline-small-functions
DEFS = -DF_CPU=16000000 -DBAUD_RATE=19200
LIBS =
CC = $(DIRAVRBIN)/avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -D$(PRODUCT) $(DEFS) -I$(DIRINC)
override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = $(DIRAVRBIN)/avr-objcopy
OBJDUMP = $(DIRAVRBIN)/avr-objdump
SIZE = $(DIRAVRBIN)/avr-size
all: $(PROGRAM).elf lst text asm size
isp: $(PROGRAM).hex
$(ISPFUSES)
$(ISPFLASH)
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.s
rm -rf *.o *.elf
rm -rf *.lst *.map
asm: $(PROGRAM).s
%.s: %.c
$(CC) -S $(CFLAGS) -g1 $^
lst: $(PROGRAM).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
size: $(PROGRAM).hex
$(SIZE) $^
# Rules for building the .text rom images
text: hex bin srec
hex: $(PROGRAM).hex
bin: $(PROGRAM).bin
srec: $(PROGRAM).srec
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@

View File

@ -0,0 +1 @@
../../ioc/avr-bootloader/main.c

View File

@ -1,8 +1,9 @@
MCU=atmega8
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000
PDEV=/dev/ttyUSB0
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -O2 -DF_CPU=16000000
LDFLAGS=-Wl,-gc-sections -Wl,-relax
CC=avr-gcc
TARGET=main
TARGET=fw_printer
OBJECT_FILES=main.o
all: $(TARGET).hex
@ -15,10 +16,14 @@ clean:
%.obj: $(OBJECT_FILES)
$(CC) $(CFLAGS) $(OBJECT_FILES) $(LDFLAGS) -o $@
avr-size -C --mcu=atmega8 main.obj
rfu: $(TARGET).hex
scp $< markus@opi:/home/markus/projects/lw35/deploy/
ssh root@opi 'lw35-tool set-mode rfu-pri; avrdude -p atmega8 -P /dev/lw35 -c arduino -b 19200 -U flash:w:/home/markus/projects/lw35/deploy/$<'
program: $(TARGET).obj
avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex
#avrdude -p $(MCU) -P /dev/ttyUSB1 -c arduino -b 57600 -U flash:w:$(TARGET).hex
avrdude -p $(MCU) -P $(PDEV) -c arduino -b 19200 -U flash:w:$(TARGET).hex
fuse:
avrdude -p m8 -c usbasp -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -7,3 +7,5 @@ INCLUDEPATH += /usr/avr/include
SOURCES += \
main.c
DEFINES += __AVR_ATmega8__

View File

@ -0,0 +1,29 @@
#!/bin/bash
source shared.sh
if [ "$1" == "" ]; then
echo "usage: $0 <file>"
exit;
fi
mkdir -p out
rm out/*
echo ".ll $LL" > out/header
cat "$1" | sed 's/\./\\\&./g' > out/text
echo ".sp 0" > out/footer
cat out/header out/text out/footer | nroff -Tascii > out/render
cline=0
page=1
while IFS="" read -r p || [ -n "$p" ]
do
cline=$(($cline + 1))
if [ $cline -eq $PL ]; then
page=$(($page + 1))
cline=0
fi
printf '%s\n' "$p" >> "out/out$page.txt"
done < out/render
echo "Created $page pages."

View File

@ -0,0 +1,39 @@
#!/bin/bash
source shared.sh
ML=$(( (110-$LL) / 2))
MT=$(( (64 - $PL) / 2 ))
echo "Margin left: $ML"
echo "Margin top : $MT"
echo "Page width : $LL"
echo "Page length: $PL"
if [ $MT -gt 127 ]; then
echo "Margin top > 127 not supported because I am lazy. Is $MT."
exit
fi
MT=$(( $MT + 128 )) # Set "move by n line bit"
#exit
echo -ne $(printf "\\\\x%02x\\\\x%02x" 224 $ML) > /dev/lw35
MR=$((ML + $LL + 2)); # Plus 2 because bug in FW in conjunction with manual newlines
echo -ne $(printf "\\\\x%02x\\\\x%02x" 225 $MR) > /dev/lw35
for file in ./out/out*; do
foo=""
while [ true ]; do
echo "Insert a piece of paper and press enter. When you're done, enter y."
read foo
if [ "$foo" == "y" ]; then
break;
fi
echo -ne "\xE3\x8C" > /dev/lw35 # Draw in until at top of paper
echo -ne $(printf "\\\\x%02x\\\\x%02x" 0xE3 $MT) > /dev/lw35 # Move over margin top
done
echo "Printing part $file..."
cat $file > /dev/lw35
echo "Part done."
done
echo "Done."

View File

@ -0,0 +1,6 @@
#!/bin/bash
# Limits for A4 vertical
LL=80 # Max 90
PL=58 # Max 64