Compare commits

..

11 commits

Author SHA1 Message Date
Keir Fraser
4925b3453a Update for v1.3 2019-05-26 15:53:24 +01:00
Keir Fraser
ee266ee6e2 DSK, IMG: Fix MFM clock pulse immediately after DAM byte (0xFB) when next data bit is 0.
Clock should be 0, but was erroneously generated as 1 because
last bit of DAM byte was forgotten.
2019-05-26 15:33:28 +01:00
Keir Fraser
01c0dba6ff index mode: Make image name checks less strict. It would reject .ST suffix. 2019-05-26 15:33:04 +01:00
Keir Fraser
c3bbf2e55f Update to v1.2 2019-04-14 18:37:14 +01:00
Keir Fraser
69ea975f5c Update HxC_Compat to v5-FF 2019-04-14 18:36:10 +01:00
Keir Fraser
de1fa12ad6 OLED: Correct horizontal offet for SH1106 128x32 displays. 2019-04-14 18:35:51 +01:00
Keir Fraser
7118f6cf40 Makefile: "make dist" includes EDSK fixup scripts 2019-03-26 11:32:47 +00:00
Keir Fraser
281b3c2f86 edsk.py: Interpret non-extended DSK images correctly. 2019-03-26 11:32:39 +00:00
Keir Fraser
82f8bbda20 Streamline the README. 2019-03-19 09:43:42 +00:00
Keir Fraser
c6c32d09ce Update for v1.1 2019-03-14 14:44:32 +00:00
Keir Fraser
cb757ba8f0 ff_cfg: Fix parsing of comma-separated values 2019-03-14 14:40:44 +00:00
134 changed files with 5076 additions and 15872 deletions

View file

@ -1,49 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set environment variables
id: vars
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Dependency packages (apt)
run: |
sudo apt update
sudo apt -y install git gcc-arm-none-eabi python3-pip srecord stm32flash zip unzip wget
- name: Dependency packages (pip)
run: python3 -m pip install --user crcmod intelhex
- name: Build dist
run: |
export VER=${{ steps.vars.outputs.sha_short }}
make -j4 dist VER=$VER
mkdir -p _cidist
mv out/flashfloppy-$VER .
rm flashfloppy-$VER/RELEASE_NOTES
git rev-parse HEAD >flashfloppy-$VER/COMMIT
zip -r flashfloppy-$VER.zip flashfloppy-$VER
mv flashfloppy-$VER.zip _cidist/
- name: Build debug dist
run: |
export VER=${{ steps.vars.outputs.sha_short }}-debug
make -j4 dist VER=$VER level=debug
mv out/flashfloppy-$VER .
rm flashfloppy-$VER/RELEASE_NOTES
git rev-parse HEAD >flashfloppy-$VER/COMMIT
echo debug >>flashfloppy-$VER/COMMIT
zip -r flashfloppy-$VER.zip flashfloppy-$VER
mv flashfloppy-$VER.zip _cidist/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: FlashFloppy.CI.${{ steps.vars.outputs.sha_short }}
path: _cidist

View file

@ -1,45 +0,0 @@
on:
push:
tags:
- 'v*.*'
name: Release
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set environment variables
id: vars
run: |
echo "ver=$(echo ${{ github.ref }} | sed -e's#.*/v##')" >> $GITHUB_OUTPUT
- name: Dependency packages (apt)
run: |
sudo apt update
sudo apt -y install git gcc-arm-none-eabi python3-pip srecord stm32flash zip unzip wget
- name: Dependency packages (pip)
run: python3 -m pip install --user crcmod intelhex
- name: Build release
run: |
export VER=${{ steps.vars.outputs.ver }}
make -j4 dist VER=$VER
mv out/flashfloppy-$VER.zip .
- name: Create Release
id: create_release
uses: ncipollo/release-action@v1
with:
tag: ${{ github.ref }}
token: ${{ secrets.GITHUB_TOKEN }}
name: FlashFloppy ${{ steps.vars.outputs.ver }}
body: "[**Release Notes:**](https://github.com/keirf/flashfloppy/blob/master/RELEASE_NOTES)"
draft: false
prerelease: false
artifacts: flashfloppy-${{ steps.vars.outputs.ver }}.zip
artifactContentType: application/zip

14
.gitignore vendored
View file

@ -1,5 +1,15 @@
*.[oa]
.*.d
*~
*.ld
*.elf
*.bin
*.hex
*.orig
*.rej
/out
/ext
*.rld
*.upd
*.dfu
/flashfloppy-*
/index.html
/HxC_Compat*

197
Makefile
View file

@ -1,144 +1,89 @@
PROJ := flashfloppy
VER := $(shell git rev-parse --short HEAD)
export FW_VER := 1.3
export FW_VER := $(VER)
PROJ := FlashFloppy
VER := v$(FW_VER)
PYTHON := python3
SUBDIRS += src bootloader reloader
.PHONY: all clean flash start serial gotek
ifneq ($(RULES_MK),y)
.DEFAULT_GOAL := gotek
export ROOT := $(CURDIR)
.PHONY: FORCE
all:
$(MAKE) -f $(ROOT)/Rules.mk all
.DEFAULT_GOAL := all
clean:
rm -f *.hex *.upd *.rld *.dfu *.html
$(MAKE) -f $(ROOT)/Rules.mk $@
prod-%: FORCE
$(MAKE) target mcu=$* target=bootloader level=prod
$(MAKE) target mcu=$* target=floppy level=prod
$(MAKE) target mcu=$* target=quickdisk level=prod
$(MAKE) target mcu=$* target=bl_update level=prod
$(MAKE) target mcu=$* target=io_test level=prod
gotek: export gotek=y
gotek: all
mv FF.dfu FF_Gotek-$(VER).dfu
mv FF.upd FF_Gotek-$(VER).upd
mv FF.hex FF_Gotek-$(VER).hex
mv BL.rld FF_Gotek-Bootloader-$(VER).rld
mv RL.upd FF_Gotek-Reloader-$(VER).upd
debug-%: FORCE
$(MAKE) target mcu=$* target=bootloader level=debug
$(MAKE) target mcu=$* target=floppy level=debug
$(MAKE) target mcu=$* target=quickdisk level=debug
$(MAKE) target mcu=$* target=bl_update level=debug
$(MAKE) target mcu=$* target=io_test level=debug
logfile-%: FORCE
$(MAKE) target mcu=$* target=bootloader level=logfile
$(MAKE) target mcu=$* target=floppy level=logfile
$(MAKE) target mcu=$* target=quickdisk level=logfile
all-%: FORCE prod-% debug-% logfile-% ;
all: FORCE all-stm32f105 all-at32f435 ;
clean: FORCE
rm -rf out
mrproper: FORCE clean
rm -rf ext
out: FORCE
+mkdir -p out/$(mcu)/$(level)/$(target)
target: FORCE out
$(MAKE) -C out/$(mcu)/$(level)/$(target) -f $(ROOT)/Rules.mk target.bin target.hex target.dfu $(mcu)=y $(level)=y $(target)=y
HXC_FF_URL := https://www.github.com/keirf/flashfloppy-hxc-file-selector
HXC_FF_URL := https://www.github.com/keirf/HxC_FF_File_Selector
HXC_FF_URL := $(HXC_FF_URL)/releases/download
HXC_FF_VER := v9-FF
HXC_FF_VER := v5-FF
_legacy_dist: PROJ := FF_Gotek
_legacy_dist: FORCE
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/$(PROJ)-$(VER).upd \
out/$(mcu)/$(level)/floppy/target.bin & \
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/alt/bootloader/$(PROJ)-bootloader-$(VER).upd \
out/$(mcu)/$(level)/bl_update/target.bin & \
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/alt/io-test/$(PROJ)-io-test-$(VER).upd \
out/$(mcu)/$(level)/io_test/target.bin & \
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/alt/logfile/$(PROJ)-logfile-$(VER).upd \
out/$(mcu)/logfile/floppy/target.bin & \
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/alt/quickdisk/$(PROJ)-quickdisk-$(VER).upd \
out/$(mcu)/$(level)/quickdisk/target.bin & \
$(PYTHON) $(ROOT)/scripts/mk_update.py old \
$(t)/alt/quickdisk/logfile/$(PROJ)-quickdisk-logfile-$(VER).upd \
out/$(mcu)/logfile/quickdisk/target.bin & \
wait
dist:
rm -rf flashfloppy-*
mkdir -p flashfloppy-$(VER)/reloader
$(MAKE) clean
$(MAKE) gotek
cp -a FF_Gotek-$(VER).dfu flashfloppy-$(VER)/
cp -a FF_Gotek-$(VER).upd flashfloppy-$(VER)/
cp -a FF_Gotek-$(VER).hex flashfloppy-$(VER)/
cp -a FF_Gotek-Reloader-$(VER).upd flashfloppy-$(VER)/reloader/
cp -a FF_Gotek-Bootloader-$(VER).rld flashfloppy-$(VER)/reloader/
$(MAKE) clean
cp -a COPYING flashfloppy-$(VER)/
cp -a README.md flashfloppy-$(VER)/
cp -a RELEASE_NOTES flashfloppy-$(VER)/
cp -a examples flashfloppy-$(VER)/
[ -e HxC_Compat_Mode-$(HXC_FF_VER).zip ] || \
wget -q --show-progress $(HXC_FF_URL)/$(HXC_FF_VER)/HxC_Compat_Mode-$(HXC_FF_VER).zip
rm -rf index.html
unzip -q HxC_Compat_Mode-$(HXC_FF_VER).zip
mv HxC_Compat_Mode flashfloppy-$(VER)
mkdir -p flashfloppy-$(VER)/scripts
cp -a scripts/edsk* flashfloppy-$(VER)/scripts/
zip -r flashfloppy-$(VER).zip flashfloppy-$(VER)
_dist: FORCE
cd out/$(mcu)/$(level)/floppy; \
cp -a target.dfu $(t)/dfu/$(PROJ)-$(n)-$(VER).dfu; \
cp -a target.hex $(t)/hex/$(PROJ)-$(n)-$(VER).hex
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/$(PROJ)-$(VER).upd \
out/$(mcu)/$(level)/floppy/target.bin $(mcu) & \
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/alt/bootloader/$(PROJ)-bootloader-$(VER).upd \
out/$(mcu)/$(level)/bl_update/target.bin $(mcu) & \
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/alt/io-test/$(PROJ)-io-test-$(VER).upd \
out/$(mcu)/$(level)/io_test/target.bin $(mcu) & \
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/alt/logfile/$(PROJ)-logfile-$(VER).upd \
out/$(mcu)/logfile/floppy/target.bin $(mcu) & \
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/alt/quickdisk/$(PROJ)-quickdisk-$(VER).upd \
out/$(mcu)/$(level)/quickdisk/target.bin $(mcu) & \
$(PYTHON) $(ROOT)/scripts/mk_update.py new \
$(t)/alt/quickdisk/logfile/$(PROJ)-quickdisk-logfile-$(VER).upd \
out/$(mcu)/logfile/quickdisk/target.bin $(mcu) & \
wait
mrproper: clean
rm -rf flashfloppy-*
rm -rf HxC_Compat_Mode-$(HXC_FF_VER).zip
dist: level := prod
dist: t := $(ROOT)/out/$(PROJ)-$(VER)
dist: FORCE all
rm -rf out/$(PROJ)-*
mkdir -p $(t)/hex
mkdir -p $(t)/dfu
mkdir -p $(t)/alt/bootloader
mkdir -p $(t)/alt/logfile
mkdir -p $(t)/alt/io-test
mkdir -p $(t)/alt/quickdisk/logfile
$(MAKE) _legacy_dist mcu=stm32f105 level=$(level) t=$(t)
$(MAKE) _dist mcu=stm32f105 n=at415-st105 level=$(level) t=$(t)
$(MAKE) _dist mcu=at32f435 n=at435 level=$(level) t=$(t)
$(PYTHON) scripts/mk_qd.py --window=6.5 $(t)/alt/quickdisk/Blank.qd
cp -a COPYING $(t)/
cp -a README $(t)/
cp -a RELEASE_NOTES $(t)/
cp -a examples $(t)/
# Clive Drive is particularly fussy about QD timings.
$(PYTHON) scripts/mk_qd.py --window=6.4 --total=7.5 --round $(t)/examples/Host/Sinclair_ZX_Spectrum/Clive_Drive/CliveDrive_Blank.qd
[ -e ext/HxC_Compat_Mode-$(HXC_FF_VER).zip ] || \
(mkdir -p ext ; cd ext ; wget -q --show-progress $(HXC_FF_URL)/$(HXC_FF_VER)/HxC_Compat_Mode-$(HXC_FF_VER).zip ; rm -rf index.html)
(cd $(t) && unzip -q ../../ext/HxC_Compat_Mode-$(HXC_FF_VER).zip)
mkdir -p $(t)/scripts
cp -a scripts/edsk* $(t)/scripts/
cp -a scripts/mk_hfe.py $(t)/scripts/
cd out && zip -r $(PROJ)-$(VER).zip $(PROJ)-$(VER)
else
all:
$(MAKE) -C src -f $(ROOT)/Rules.mk $(PROJ).elf $(PROJ).bin $(PROJ).hex
bootloader=y $(MAKE) -C bootloader -f $(ROOT)/Rules.mk \
Bootloader.elf Bootloader.bin Bootloader.hex
reloader=y $(MAKE) -C reloader -f $(ROOT)/Rules.mk \
Reloader.elf Reloader.bin Reloader.hex
srec_cat bootloader/Bootloader.hex -Intel src/$(PROJ).hex -Intel \
-o FF.hex -Intel
$(PYTHON) ./scripts/mk_update.py src/$(PROJ).bin FF.upd
$(PYTHON) ./scripts/mk_update.py bootloader/Bootloader.bin BL.rld
$(PYTHON) ./scripts/mk_update.py reloader/Reloader.bin RL.upd
$(PYTHON) ./scripts/dfu-convert.py -i FF.hex FF.dfu
endif
BAUD=115200
DEV=/dev/ttyUSB0
SUDO=sudo
STM32FLASH=stm32flash
T=out/$(target)/target.hex
ocd: FORCE all
$(PYTHON) scripts/openocd/flash.py $(T)
flash:
sudo stm32flash -b $(BAUD) -w FF_Gotek-$(VER).hex /dev/ttyUSB0
flash: FORCE all
$(SUDO) $(STM32FLASH) -b $(BAUD) -w $(T) $(DEV)
start:
sudo stm32flash -b $(BAUD) -g 0 /dev/ttyUSB0
start: FORCE
$(SUDO) $(STM32FLASH) -b $(BAUD) -g 0 $(DEV)
serial: FORCE
$(SUDO) miniterm.py $(DEV) 3000000
serial:
sudo miniterm.py /dev/ttyUSB0 3000000

75
README
View file

@ -1,75 +0,0 @@
FlashFloppy
===========
Keir Fraser <keir.xen@gmail.com>
https://github.com/keirf/flashfloppy
This distribution contains FlashFloppy custom firmware for Gotek and
Gotek-compatible hardware.
FlashFloppy documentation and downloads:
https://github.com/keirf/flashfloppy/wiki/
Supported Microcontrollers
--------------------------
FlashFloppy supports two types of STM32-like microcontroller:
STM32F105 (and the compatible AT32F415)
- 72MHz Cortex-M3, 128kB Flash, 64kB RAM (AT32F415: 32kB RAM)
AT32F435
- 288MHz Cortex-M4, 256kB Flash, 384kB RAM
If you want to know which type of MCU you have, you can open your Gotek and
read the writing on the square chip on your Gotek PCB.
Firmware Programming
--------------------
If programming a factory-fresh Gotek running factory firmware, you will need
to program a HEX or DFU firmware file as explained in the wiki, linked above.
These files are located in the hex/ and dfu/ folders respectively, and you
must use the correct file for your microcontroller:
STM32F105, AT32F415
- Use file "dfu/flashfloppy-at415-st105-<ver>.dfu" (or .hex equivalent)
AT32F435
- Use file "dfu/flashfloppy-at435-<ver>.dfu" (or .hex equivalent)
Firmware Update
---------------
Once FlashFloppy has been flashed to a device (using a HEX or DFU file),
further updates can be made via an Update file on a USB drive, as described
in the wiki.
To support older versions of the FlashFloppy bootloader, two types of
Update file are included in the distribution, distinguishable by name:
FF_Gotek-*.upd: Legacy Update file
- All STM32F105/AT32F415 devices
flashfloppy-*.upd: Universal Update file
- All AT32F435 devices
- STM32F105/AT32F415 devices running a recent FlashFloppy bootloader
Each update format will only work with a device (and FlashFloppy bootloader)
that supports it. If you are unsure which to use, it is okay to copy both
Update file types to your USB drive: the bootloader will correctly load just
one of the Update file types that it supports.
Alternatively try one Update file at a time, and switch to the other type if
you see error E01 on the Gotek display.
Alternative Firmwares
---------------------
In the alt/ folder you will find (pairs of) Update files implementing
alternative firmwares. Most users can ignore these, and use only the
Update files in the root of the distribution.
The alternative firmwares include:
* alt/bootloader: Updates your Gotek bootloader
- WARNING: Proceed with caution. Read the Firmware Update page on the wiki.
* alt/io-test: Test your Gotek I/O pins if you suspect a hardware fault
* alt/quickdisk: QuickDisk emulation (see the wiki)
- If you don't know what QuickDisk is, you don't need this firmware.
* alt/logile: Firmware with debug logging to FFLOG.TXT on the USB drive
- Useful only for fault finding. Not for general use.
Redistribution
--------------
Source code, and all binary releases, are freely redistributable in
any form. Please see the the COPYING file included in this
distribution.

View file

@ -1,32 +1,26 @@
# FlashFloppy
*The #1 floppy emulator.*
![CI Badge][ci-badge]
![Downloads Badge][downloads-badge]
![Version Badge][version-badge]
<img src="https://raw.githubusercontent.com/wiki/keirf/flashfloppy/assets/banner.jpg">
**FlashFloppy** is a floppy-drive emulator for the ubiquitous
[**Gotek**][Gotek-Compatibility] hardware. Connect to retro machines just
like a real floppy drive but use disk images on a modern USB stick!
- Say goodbye to old and unreliable floppy disks
- Download and play from the disk-image archives for your retro machines
**FlashFloppy** is the **#1 floppy emulator**:
- Supports a [massive range][Host-Platforms] of retro computers, synths, and machinery
- Directly reads and writes [many image formats][Image-Formats]
A retro floppy emulator for the ubiquitous Gotek hardware.
- Directly supports a [wide range of image formats][Image-Formats]
- [Flexible track layout][Track-Layouts] for Raw Sector Images
- [Extremely configurable][FF.CFG-Configuration-File]
**FlashFloppy** is **Free and Open-Source Software**.
## Download
- [**Download FlashFloppy**][Downloads]
## Documentation
- [**Read the GitHub Wiki**](https://github.com/keirf/flashfloppy/wiki)
- [**Read the GitHub Wiki**](https://github.com/keirf/FlashFloppy/wiki)
## Donations
FlashFloppy is a labour of love: working on it takes a **lot** of time
and effort. The development of new features, plus maintenance, bug
fixing, testing, release preparations and so on is a huge undertaking;
and that ignores non-development tasks such as writing documentation
and community management.
If you would like to **support FlashFloppy's development**, please see
the [**Donations page**][Donations].
## Redistribution
@ -44,13 +38,8 @@ file on your selling page. For example:
- FlashFloppy is free software. For more information see the
[license](COPYING).
[Gotek-Compatibility]: https://github.com/keirf/flashfloppy/wiki/Gotek-Compatibility
[Host-Platforms]: https://github.com/keirf/flashfloppy/wiki/Host-Platforms
[Image-Formats]: https://github.com/keirf/flashfloppy/wiki/Image-Formats
[Track-Layouts]: https://github.com/keirf/flashfloppy/wiki/Track-Layouts
[FF.CFG-Configuration-File]: https://github.com/keirf/flashfloppy/wiki/FF.CFG-Configuration-File
[Downloads]: https://github.com/keirf/flashfloppy/wiki/Downloads
[ci-badge]: https://github.com/keirf/flashfloppy/workflows/CI/badge.svg
[downloads-badge]: https://img.shields.io/github/downloads/keirf/flashfloppy/total
[version-badge]: https://img.shields.io/github/v/release/keirf/flashfloppy
[Image-Formats]: https://github.com/keirf/FlashFloppy/wiki/Image-Formats
[Track-Layouts]: https://github.com/keirf/FlashFloppy/wiki/Track-Layouts
[FF.CFG-Configuration-File]: https://github.com/keirf/FlashFloppy/wiki/FF.CFG-Configuration-File
[Downloads]: https://github.com/keirf/FlashFloppy/wiki/Downloads
[Donations]: https://github.com/keirf/FlashFloppy/wiki/Donations

View file

@ -3,401 +3,22 @@
** Keir Fraser <keir.xen@gmail.com>
************************************
** v3.42 - 11 January 2024
- HFEv3: Various read/write improvements
- WDATA: Merge short write pulses, and apply de-jitter/precomp
- IMG, EDSK: Stream large sector writes to flash
** v1.3 - 26 May 2019
- Indexed mode: Fix for *.ST images
- MFM generation: Fix small error for DSK and IMG
** v3.41 - 14 July 2023
- AT32F415: Fix timer handling since clock speed increase (v3.39).
- LCD: Faster power-on initialisation. Don't wait for display to clear.
** v3.40 - 27 June 2023
- XDF: Fix writes to side 1 of XDF disk images
- HFE: Better handling of long No Flux Areas
- QuickDisk: Reduce motor spinup time to 1 second (previously 2 seconds)
- LCD: Completely blank display when backlight is off
** v3.39 - 1 March 2023
- AT32F415: Run this MCU at 144MHz (previously 72MHz).
- HFE: Fix HFEv3 support. Support Dungeon Master & Chaos Strikes Back.
- IMG.CFG: Support mixed sector sizes per track (Ensoniq Mirage etc).
- IMG.CFG: New option img_bps= allows padding of short sectors in IMG files.
- FF.CFG: New option notify-volume= for notifying on insert/eject events.
- FF.CFG: New OLED display sub-option 'hflip' horizontally flips display.
- Various other small fixes.
** v3.38 - 4 December 2022
- AT32F435: Fix RDATA release on drive deassert
- SF7: Support Sega SF-7000 *.SF7 images
** v3.37 - 20 October 2022
- Amiga: Fix firmware crash when mounting read-only disk image
- Since v3.36 when interface=amiga and motor-delay= is configured
- Amiga: Respect MOTOR when motor-delay= is configured and disk ejected
- Previously the MOTOR signal was ignored when no disk inserted
** v3.36 - 10 October 2022
- AT32F435: Fix SD card handling on boards which support it
- FF.CFG, OSD: New options osd-columns= and osd-display-order=
- Amiga: Improved pin 34 ID/RDY emulation
- Requires AT32F435 MCU and MOR jumper strap
- Requires FF.CFG options: interface=amiga, motor-delay=500
** v3.35 - 4 August 2022
- AT32F435: Fix Quick Disk firmware
** v3.34 - 4 July 2022
- AT32F435: Fix startup to MCU spec (LDO voltage, Flash clock divisor)
- AT32F435: Cache HFE and QD image data, since there is plenty of RAM
- Allow rotary encoder on pins PA13/PA14 on any board except QFN32 MCU
- io-test: Fix io-test alt firmware for modern Gotek boards
** v3.33 - 20 June 2022
- Support new board SFRKC30.AT4.35
- Support new chip AT32F435 (288MHz M4, 256kB+ Flash, 384kB SRAM)
- New UPD file format and explanatory README: Please read!
** v3.32 - 28 May 2022
- Fix 'oled-font=8x16' option (broken in release 3.31)
- Improve drive-select ISR performance
- Fixes issues with fast Amiga accelerators
** v3.31 - 23 May 2022
- Fix Gotek drive detection with Amiga Kickstart ROM v3.2.1
- QD: FF.CFG alternative to JC jumper (no JC on SFRKC30.AT2 model)
- Place "interface=ibmpc" in FF.CFG
- OLED: New "-slow" modifier to slow down I2C bus for glitchy displays
- AUTOBOOT: Disallow writes to MBR, which can trash the USB drive
** v3.30 - 26 January 2022
- IMG.CFG: New option step= allows to specify double-step operation
- FF.CFG: New option max-cyl= allows limiting head-step range
- SFRKC30 Gotek Models: Improved rotary support on new "KC30" header
** v3.29 - 2 October 2021
- Support new Gotek board SFRKC30.AT2 using AT32F415KBU7-4 (QFN32)
- Support LQFP64 AT32F415RxT7 chips on existing "Enhanced Gotek" boards
- IMG: Fix default GAP2 for ED (eg. 2.88M) images
- IMG.CFG: New parameter gap2= to set Post-ID Gap value
** v3.28 - 2 July 2021
- Gotek model SFR1M44-U100LQD: Fix occasional rotary encoder issue
- This model uses SFRKC40.AT4.7 PCB with encoder on new pin header
- Rotary encoder would occasionally not be detected at power on
** v3.27 - 2 July 2021
- Fix v3.26 regression in button handling for GOEX hardware
** v3.26 - 24 June 2021
- Support new Gotek board SFRKC30.AT4.7
** v3.25 - 25 April 2021
- IMG, DSK: Fix track formatting on Artery microcontrollers
- Firmware would crash during format operations
** v3.24 - 15 April 2021
- Beta support for new Artery microcontrollers used on latest Gotek models
- See the wiki for more details
- https://github.com/keirf/FlashFloppy/wiki/Gotek-Compatibility
- IMG: Fix skew/interleave on MSDMF (1.68M) images
** v3.23 - 31 December 2020
- OLED/LCD: Fix missing folder name display row when inserting USB drive
- IMG.CFG: New examples for Roland, Sinclair QL, Kaypro
- IMG.CFG: Now supported in HxC-compat and indexed navigation modes
- IMG: Fix default 8-inch single-density data rate
- IMG, HFE: Support 255-cylinder image files
** v3.22 - 17 November 2020
- Fix various crashes when mounting a Flash drive with stale IMAGE_A.CFG
- FAT FS: Support filesystems for which cluster table is "too small"
- Windows and Linux will mount these volumes, thus so should we
- FF.CFG: New OLED display-type option: -inverse
- Reverse-video effect (black text on white background)
- FF.CFG: display-order= option affects normal display modes only
- Ignored in all banner and menu modes, to avoid jumbled display
- FF.CFG: Fix display-type parsing for OLED-specific options
- Ignore them unless an OLED display is explicitly configured
** v3.21 - 26 October 2020
- Support GUID Partition Table (GPT)
- Now support: GPT, MBR, and no partition table
- FatFS: Updated to R0.14, patchlevel 2
** v3.20 - 15 October 2020
- Eject Menu: Replace Clone with Copy/Paste
- Allows an image to be copied to a different folder
- Navigation mode: Copy to selected folder by holding Select for 1.5s
- FF.CFG: New option "rotary=v2" to use v2.x encoder logic
- Fixes a very few encoders which don't work with stricter v3.x logic
- FF.CFG: New option "twobutton-action=htu"
- Implements hundreds/tens/units button actions of the factory firmware
- IMG.CFG: New parameters:
- tracks: Track-scoped parameter lists (geometry can vary by track)
- h: Override default IDAM Head field
- gap4a: Override default post-index track gap
- IMG.CFG: Tag names are now case insensitive
- IMG.CFG: Tag by file size and/or name
- IMG.CFG: Implement some example configurations under examples/Host/
- IMG: Fix some of the more bizarre default track geometries
** v3.19 - 28 September 2020
- Amiga, ADF: Fix X-Copy verified writes with out-of-order sectors
- Remember the latest written sector order for current cylinder
- Forgotten after head step or disk eject but sufficient for X-Copy
- FF.CFG: New interface= options 'jppc' and 'jppc-hdout'
- jppc: pin2=nc, pin34=RDY, Japanese PC standard
- jppc-hdout: As above but pin2=HD_OUT, similar to ibmpc-hdout
- akai-s950 is retained as a legacy alias for jppc-hdout
** v3.18 - 23 September 2020
- OLED/LCD: Fix potential minor display corruption
- Only seen with 128x64 OLED displays, bottom right corner
- alt/logfile: Write FFLOG.TXT to correct folder (root or FF/)
- IMG, DSK: Various cleanups to sector-write handling
** v3.17 - 17 September 2020
- DSK: Fix infinite loop when trying to open a bad DSK image file
- Quick Disk: Restart read stream immediately after a write
- QD support now works on Sharp MZ-800
- IMG.CFG: Remove [default] stanza from example config
- Users copying the example file will no longer break their IMG files
** v3.16 - 22 August 2020
- Rotary encoder: Velocity curve during image navigation
- Fast spin of the encoder skips multiple entries per click
- LCD/OLED/OSD: Fix image name when display is wider than 24 characters
- HFE: Fix double-step HFE images (broken since v3.14a)
- HxC Compat: Strip filename extension from image name display row
** v3.15 - 23 July 2020
- New stable release series
- Improve rotary encoder robustness by sampling at 4x higher rate
** v3.14a - 15 July 2020
- Properly implement non-existent tracks as empty / unformatted
- In particular this avoids writing tracks beyond end of disk image
- See issue #309: Could corrupt HFE images
- Akai IMG: Implement track skew (faster access and fixes Oberheim DPX)
- Speaker: Rate-limit step pulses at the speaker
- Avoids high-freq chirp in Direct Access mode and Gotek-aware fast loaders
- HxC Compat, v9-FF:
- Atari ST keymap is now QWERTY
- Remove unused settings from drive setup menu
- Fix the search/filter box (Esc and Backspace keys)
** v3.13a - 13 March 2020
- FF.CFG: New option 'write-drain=eot'
- Fixes writes to Gotek on Amstrad PPC series (#320)
- FF.CFG: New option 'display-on-activity=sel'
- Turns on display whenever the Gotek drive is selected by host
- HFE: Respect double-step header flag
- Fixes 180k disk images on Amstrad PCW (#318)
** v3.12a - 7 February 2020
- IMG: Support IBM 3174 1.2M and 2.4M formats (host=ibm-3174)
- HxC: Fix HxC mode with no file selector (AUTOBOOT.HFE)
- FF OSD: Fix dual-display operation with slower OLED
- Wait for OLED to initialise when display-type=oled...
** v3.11a - 30 December 2019
- LCD/OLED: Fix subfolder name, as shown in 3- & 4-row displays
- Subfolder wasn't updated correctly when moving to parent (..) folder
** v3.10a - 28 December 2019
- Bootloader: Wait for buttons to be pressed then released...
- ...before starting firmware update process
- Avoids an infinite loop when reprogramming Bootloader itself
** v3.9a - 27 December 2019
- IMG: Fix density-select pin output for HD images
- Fixes 'pin02=dens' and 'interface=ibmpc-hdout'
- Bug has existed since v2.2a
- Rotary Encoder: Improve tracking
- Higher frequency, and better debounce algorithm
** v3.8a - 10 December 2019
- USB: Fix buffer overflow when parsing string descriptors
- Fixes crash with recent SanDisk Ultra Fit drives
- HxC Compat, v8-FF: Fixes startup crash on Atari ST
- Amiga: Fixes for "interface = amiga" setting
- TR-DOS (TRD): Fix geometry when TR-DOS header is incomplete
- Quick Disk: Larger read/write window in default blank image
- GCC9 build fixes
** v3.7a - 11 November 2019
- Quick Disk Bug Fixes
- Fix write offsets and lengths within QD track
- Filter ADF images from navigator: only QD images supported
- Extra logging in FFLOG.TXT for debug purposes
- Amiga AutoSwap new title: Gobliiiins
- Thanks to Arkadiusz Makarenko!
- https://github.com/keirf/flashfloppy-autoswap/wiki/Downloads
** v3.6a - 13 October 2019
- Quick Disk Initial Release
- New firmware and blank QD image in alt/quickdisk
- Documentation in the Wiki
- Update HxC Compat to v7-FF
- Fix failure when booted on unmodded A1200 ESCOM boards
** v3.5a - 9 October 2019
- New Main Menu: Press Prev/Next or Select with no Flash drive inserted
- Factory Reset, Firmware Update, OSD Config
- OSD: Must be updated to latest version: v1.7 or later!
- OSD: Receive Gotek button commands via I2C
- OSD: Default to 40 columns if no other display is connected
- TR-DOS (TRD): Fix geometry detection based on TR-DOS header
** v3.4a - 25 September 2019
- FF OSD support
- Bus sharing with existing LCD/OLED display
- Gotek buttons can be remoted to FF OSD for OSD configuration
** v3.3a - 8 July 2019
- FF.CFG: New Disk-Change Reset option: chgrst=delay-N
- Automatically clears the DSKCHG signal Nx0.5s after disk insertion
- chgrst=delay-3 fixes Disk Change on Ensoniq EPS synths
- Change head-step signal handling to reduce interrupt rate
- OLED/LCD: Fix current-folder display line for image-on-startup=init|static
- image-on-startup=static: The static image is now specified in INIT_A.CFG
** v3.2a - 25 June 2019
- OLED: New default layout for 128x64 displays
- LCD: Support 20x4 character displays
- LCD: Row ordering is configurable
- FF.CFG: Rename oled-text= to display-order= to reflect this
- Eject menu: Confirmation required for Delete/Clone operations
- Trackball: Reduce jitteriness by adding simple inertia
** v3.1a - 13 June 2019
- OLED: Text height and content can be configured (FF.CFG:oled-text=)
- New default for 128x64 displays presents a new third text row
- LCD/OLED: Present an action menu when an image is ejected
- Includes Clone and Delete Image operations
** v3.0a - 10 June 2019
- Disk Change Reset: Emulate explicit Reset signal of certain vintage drives
- Requires a hardware modification and FF.CFG: chgrst=pa14
- Support ZHONGJY_TECH 2.23" 128x32 displays based on SSD1305 controller
- FF.CFG: display-type=oled-128x32-ztech
** v2.13 - 7 June 2019
- HFE: Fix read buffering error
- Update HxC Compat to v6-FF
- More robust error checking on writes
** v2.12 - 2 June 2019
- HFEv3: Support flaky/weak bytes
- LCD/OLED: Improve power-on initialisation robustness
- Roland: Direct support for *.OUT images
- IO-Test: New alternative firmware to test Gotek I/O pins
- https://github.com/keirf/flashfloppy/wiki/Testing-IO-Pins
** v2.11a - 23 May 2019
- Simpler bootloader update process with all-in-one update file
- Update firmware via SD card (enhanced Goteks with SD card slot)
- FF.CFG: sort-priority= to prioritise folders vs files during navigation
- Default: Folders are listed before files
** v2.10a - 20 May 2019
- Fix breakages since v2.2a:
- host=acorn: *.ADF handling
- host=tandy-coco: *.DSK handling
** v2.9a - 17 May 2019
- FF.CFG: New option motor-delay= to provide emulation of motor behaviour
- Requires modification of a standard Gotek PCB (see Wiki: Hardware Mods)
- Debug logging: An alternative firmware is provided to log to FFLOG.TXT
- Find the alternative update file in alt/logfile/
- Use this for personal interest or as directed by me for debugging
- Not for general use!
- IMG/DSK: Better RAM handling (more space for mass-storage block cache)
- Code optimisation (MFM decode speeded up 4x)
- Small fix to generate INDEX signal when starting read near end of track
** v2.8a - 10 May 2019
- DSK, IMG: Fix small error in generated MFM data
- Increase write buffer to 32kB, enough for a full high-density track
- More reliable whole-track writes, especially to HFE images
** v2.7a - 23 April 2019
- Sort folders into alphabetical order during direct navigation
- FF.CFG: folder-sort= to modify this new default behaviour
- Fix memory corruption issues (stack overflow)
- ATR: Interleave sectors for best performance over slow SIO interface
** v2.6a - 14 April 2019
- Fix feature breakages in v2.5a
- SSD/DSD/TRD auto-extend feature
- FF.CFG: eject-on-startup=yes feature
** v1.2 - 14 April 2019
- OLED: Fix horizontal offset on SH1106 128x32 displays
- Update HxC Compat to v5-FF
** v2.5a - 12 April 2019
- Fragment-offsets cache implemented at the FAT filesystem layer
- Block cache implemented at the mass-storage volume layer
- Faster image selection/navigation in large folders
- Improved reliability in image handling (reduced access latencies)
- USB stick will usually stop flashing when drive is not being accessed!
- FF.CFG: New rotary input options
- 'trackball': Blackberry-style trackball
- 'buttons': Push-to-ground Prev/Next buttons
** v2.4a - 9 April 2019
- This release fixes many raw track formats (SSD, DSD, OPD, VDK, ...)
- Thanks to John Gray for bug report, and testing!
- RAW: Fix FM track generation
- FM and IAM flags not plumbed through from front-end image handlers
- RAW: Fix interleaved/skewed track generation
- Data fetch not loading sectors from image file in the right order
** v2.3a - 8 April 2019
- OLED: Auto-detect SSD1306 vs SH1106 display controller
- FF.CFG: 'display-type = ...-sh1106' is now redundant and ignored
- ATR: Fix readability of downloaded ATR images
- Invert data as it is read/written, mirroring the standard XF551 interface
- Thanks to Piotr for this report (using his XF551 clone)
** v2.2a - 5 April 2019
- New image types supported:
- XDF: 3.5" HD eXtended Disk Format (1840kB)
- ATR: Atari 8-bit
- 7-Seg LED: Improved track display.
- Remove option 'led-trk' from FF.CFG. Track display mode is always on.
- OLED: Fix horizontal offset on SH1106 128x32 displays
- IMG.CFG: 'id' parameter simplified; 'sskew' renamed 'hskew' (head skew)
** v2.1a - 26 March 2019
- IMG.CFG: Allow up to 256 sectors per track
- IMG.CFG: Split skew into per-cylinder and per-side values (cskew/sskew)
- IMG.CFG: Introduce image-file layout option (file-layout=<csv-list>):
- sequential,interleaved: Cylinder-first or side-first track ordering
- reverse-sideN: Side-N cylinders in reverse order (high to low) (N=0,1)
- sides-swapped: Ordering of disk sides is swapped in the image file
- 7-Segment LED: Display track number when an image is mounted
- FF.CFG: "display-type = led-trk"
- Displays slot number as usual during image selection/navigation
- First button press reverts to slot display; Next press begins navigation
- LCD/OLED: Display full cylinder number on displays wider than 16 columns
- Previously truncated at cylinder 99
** v2.0a - 14 March 2019
- IMG: Allow geometry to be manually configured in new file IMG.CFG
- See examples/IMG.CFG for documentation
- Multiple formats can be defined; distinguished by image name tags
- IMG: Support FM mode with Index Address Mark (IAM)
- IMG: Support auto-configuration of GAP3 (post data gap) when using IMG.CFG
** v1.1 - 14 March 2019
- FF.CFG: Fix parsing of comma-separated values
- Indexed Mode: Allow arbitrary image name after "DSKAnnnn" prefix
- eg. DSKA0000_myimage.img, DSKA0002_another.adf
- Indexed Mode: Allow the "DSKA" prefix to be changed (FF.CFG:indexed-prefix=)
** v1.0 - 4 February 2019
- Game/demo AutoSwap-disks feature
- No manual disk swapping, at all!
- Requires patching of host software titles
- Amiga titles so far (github:keirf/flashfloppy-autoswap):
- Amiga titles so far (github:keirf/FF_AutoSwap):
- Beneath a Steel Sky
- Indiana Jones and the Fate of Atlantis
- The Secret of Monkey Island

View file

@ -3,7 +3,7 @@ CC = $(TOOL_PREFIX)gcc
OBJCOPY = $(TOOL_PREFIX)objcopy
LD = $(TOOL_PREFIX)ld
PYTHON = python3
PYTHON = python
ifneq ($(VERBOSE),1)
TOOL_PREFIX := @$(TOOL_PREFIX)
@ -13,39 +13,21 @@ FLAGS = -g -Os -nostdlib -std=gnu99 -iquote $(ROOT)/inc
FLAGS += -Wall -Werror -Wno-format -Wdeclaration-after-statement
FLAGS += -Wstrict-prototypes -Wredundant-decls -Wnested-externs
FLAGS += -fno-common -fno-exceptions -fno-strict-aliasing
FLAGS += -mlittle-endian -mthumb -mfloat-abi=soft
FLAGS += -Wno-unused-value -ffunction-sections
## STM32F105
ifeq ($(mcu),stm32f105)
FLAGS += -mcpu=cortex-m3 -DSTM32F105=1 -DMCU=1
ifeq ($(bootloader),y)
# Debug bootloader doesn't fit in 32kB
override debug=n
override logfile=n
endif
## AT32F435
else ifeq ($(mcu),at32f435)
FLAGS += -mcpu=cortex-m4 -DAT32F435=4 -DMCU=4
endif
FLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
FLAGS += -Wno-unused-value
ifneq ($(debug),y)
FLAGS += -DNDEBUG
endif
ifeq ($(reloader),y)
FLAGS += -DRELOADER=1
endif
ifeq ($(bootloader),y)
FLAGS += -DBOOTLOADER=1
endif
ifeq ($(logfile),y)
FLAGS += -DLOGFILE=1
endif
ifeq ($(quickdisk),y)
FLAGS += -DQUICKDISK=1
endif
FLAGS += -MMD -MF .$(@F).d
DEPS = .*.d
@ -55,11 +37,12 @@ CFLAGS += $(CFLAGS-y) $(FLAGS) -include decls.h
AFLAGS += $(AFLAGS-y) $(FLAGS) -D__ASSEMBLY__
LDFLAGS += $(LDFLAGS-y) $(FLAGS) -Wl,--gc-sections
SRCDIR := $(shell $(PYTHON) $(ROOT)/scripts/srcdir.py $(CURDIR))
include $(SRCDIR)/Makefile
RULES_MK := y
include Makefile
SUBDIRS += $(SUBDIRS-y)
OBJS += $(OBJS-y) $(OBJS-^n) $(patsubst %,%/build.o,$(SUBDIRS))
OBJS += $(OBJS-y) $(patsubst %,%/build.o,$(SUBDIRS))
# Force execution of pattern rules (for which PHONY cannot be directly used).
.PHONY: FORCE
@ -73,14 +56,21 @@ build.o: $(OBJS)
$(LD) -r -o $@ $^
%/build.o: FORCE
+mkdir -p $*
$(MAKE) -f $(ROOT)/Rules.mk -C $* build.o
%.ld: $(SRCDIR)/%.ld.S $(SRCDIR)/Makefile
%.o: %.c Makefile
@echo CC $@
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.S Makefile
@echo AS $@
$(CC) $(AFLAGS) -c $< -o $@
%.ld: %.ld.S Makefile
@echo CPP $@
$(CC) -P -E $(AFLAGS) $< -o $@
%.elf: $(OBJS) %.ld $(SRCDIR)/Makefile
%.elf: $(OBJS) %.ld Makefile
@echo LD $@
$(CC) $(LDFLAGS) -T$(*F).ld $(OBJS) -o $@
chmod a-x $@
@ -89,25 +79,23 @@ build.o: $(OBJS)
@echo OBJCOPY $@
$(OBJCOPY) -O ihex $< $@
chmod a-x $@
$(PYTHON) $(ROOT)/scripts/check_hex.py $@ $(mcu)
ifneq ($(bootloader),y)
srec_cat ../bootloader/target.hex -Intel $@ -Intel -o $@ -Intel
endif
%.bin: %.elf
@echo OBJCOPY $@
$(OBJCOPY) -O binary $< $@
chmod a-x $@
%.dfu: %.hex
$(PYTHON) $(ROOT)/scripts/dfu-convert.py -i $< $@
%.o: $(SRCDIR)/%.c $(SRCDIR)/Makefile
%.o: $(RPATH)/%.c Makefile
@echo CC $@
$(CC) $(CFLAGS) -c $< -o $@
%.o: $(SRCDIR)/%.S $(SRCDIR)/Makefile
%.o: $(RPATH)/%.S Makefile
@echo AS $@
$(CC) $(AFLAGS) -c $< -o $@
clean:: $(addprefix _clean_,$(SUBDIRS) $(SUBDIRS-n) $(SUBDIRS-))
rm -f *.orig *.rej *~ *.o *.elf *.hex *.bin *.ld $(DEPS)
_clean_%: FORCE
$(MAKE) -f $(ROOT)/Rules.mk -C $* clean
-include $(DEPS)

View file

@ -8,7 +8,6 @@ GPIn: (all must be 5v tolerant, *=not)
PB9 WGATE
PB4 SIDE
PA15 MOTOR [Enhanced Boards only]
PB15 MOTOR [Standard board mod: pin 5 of SPI Flash footprint]
GPOut:
PB7 CHNG
PB8 INDEX

View file

@ -0,0 +1,7 @@
#define FLASH_BASE 0x08000000
#define FLASH_LEN 32K
#define RAM_BASE 0x20000000
#define RAM_LEN 64K
#include "../scripts/stm32f10x.ld.S"

28
bootloader/Makefile Normal file
View file

@ -0,0 +1,28 @@
RPATH = ../src
OBJS += update.o
OBJS += fpec.o
OBJS += build_info.o
OBJS += cancellation.o
OBJS += crc.o
OBJS += vectors.o
OBJS += fs.o
OBJS += spi.o
OBJS += string.o
OBJS += stm32f10x.o
OBJS += time.o
OBJS += timer.o
OBJS += util.o
OBJS += volume.o
OBJS += flash_cfg.o
OBJS-$(debug) += console.o
SUBDIRS += display
SUBDIRS += fatfs
SUBDIRS += gotek
SUBDIRS += usb
.PHONY: $(RPATH)/build_info.c
build_info.o: CFLAGS += -DFW_VER="\"$(FW_VER)\""

View file

@ -0,0 +1,6 @@
RPATH = ../../src/display
OBJS += display.o
OBJS += lcd.o
OBJS += oled_font_6x13.o
OBJS += led_7seg.o

View file

@ -0,0 +1,4 @@
RPATH = ../../src/fatfs
OBJS += ff.o
OBJS += ffunicode.o

View file

@ -0,0 +1,3 @@
RPATH = ../../src/gotek
OBJS += board.o

8
bootloader/usb/Makefile Normal file
View file

@ -0,0 +1,8 @@
RPATH = ../../src/usb
OBJS += usb_bsp.o
OBJS += usbh_msc_fatfs.o
SUBDIRS += stm32_usbh_msc
usb%.o: CFLAGS += -I$(ROOT)/src/usb/stm32_usbh_msc/inc/ -include usbh_conf.h

View file

@ -0,0 +1,14 @@
RPATH = ../../../src/usb/stm32_usbh_msc
OBJS += usb_core.o
OBJS += usb_hcd.o
OBJS += usb_hcd_int.o
OBJS += usbh_core.o
OBJS += usbh_hcs.o
OBJS += usbh_ioreq.o
OBJS += usbh_msc_bot.o
OBJS += usbh_msc_core.o
OBJS += usbh_msc_scsi.o
OBJS += usbh_stdreq.o
CFLAGS += -I$(ROOT)/src/usb/stm32_usbh_msc/inc/ -include usbh_conf.h

View file

@ -1,23 +1,19 @@
## FF.CFG: Example FlashFloppy Configuration File
# Place in the root folder or FF/ subfolder of your USB drive.
# NOTE: If FF/ exists, IMG.CFG must reside there, not the root folder.
# Uncommented lines below are the default settings.
# Uncommented options cannot be overridden by settings in other config files.
##
## DRIVE EMULATION
# Floppy-drive interface mode (interface pins 2 and 34)
# jc: Specified by jumper JC (open: shugart, closed: ibmpc)
# shugart: P2=DSKCHG, P34=RDY (Amiga, Atari ST, many others)
# ibmpc: P2=unused, P34=DSKCHG (IBM PC interface)
# ibmpc-hdout: P2=HD_OUT, P34=DSKCHG (not generally needed: prefer ibmpc)
# jppc: P2=unused, P34=RDY (Japanese PC standard)
# jppc-hdout: P2=HD_OUT, P34=RDY (Japanese PC alternate: prefer jppc)
# akai-s950: Legacy alias of jppc-hdout, previously used for Akai S950
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer shugart)
# Floppy-drive interface mode
# shugart: P2=DSKCHG, P34=RDY
# ibmpc: P2=unused, P34=DSKCHG
# ibmpc-hdout: P2=HD_OUT, P34=DSKCHG (not generally needed: prefer 'ibmpc')
# akai-s950: P2=HD_OUT, P34=RDY (Akai S950)
# amiga: P2=DSKCHG, P34=DRIVE_ID (not generally needed: prefer 'shugart')
# jc: JC closed: ibmpc, JC open: shugart
interface = jc
# Host platform: Improves image-format detection for generic types such as IMG
@ -28,7 +24,7 @@ interface = jc
# ensoniq: Ensoniq (ASR, TS, etc)
# fluke: Fluke 9100
# gem: General Music (S2, S3)
# ibm-3174: IBM 3174 Establishment Controller
# kaypro: Kaypro
# memotech: Memotech
# msx: MSX
# nascom: Nascom
@ -59,28 +55,16 @@ pin34 = auto
# Values: yes | no
write-protect = no
# Maximum cylinder that can be stepped to (255 is required for access to
# Direct Access mode as used by image-selector utilities and Autoswap games).
# Values: 0 <= N <= 255
max-cyl = 255
# Filter glitches in the SIDE-select signal shorter than N microseconds
# Values: 0 <= N <= 255
side-select-glitch-filter = 0
# Rotational offset of disk after a track change
# Rotational offset of data after a track change
# instant: No rotation during track change
# realtime: Emulate rotation of disk while track is changing
# Values: instant | realtime
track-change = instant
# Rotational offset of disk after draining a write to Flash
# instant: No rotation
# realtime: Disk rotates in real time during drain
# eot: Disk rotates to (near) end of track
# Values: instant | realtime | eot
write-drain = instant
# Index pulses suppressed when RDATA and WDATA inactive?
# Values: yes | no
index-suppression = yes
@ -89,19 +73,6 @@ index-suppression = yes
# Values: 0 <= N <= 255
head-settle-ms = 12
# Milliseconds delay from motor-on to drive ready.
# On a standard unmodified Gotek the motor signal is not connected and a
# non-default value here will have no effect. Most systems and software do
# not care about correct motor behaviour, and default (ignore) works fine.
# Values: ignore | 0 <= N <= 1000
motor-delay = ignore
# What causes the disk-change (chg) signal to reset after disk insertion?
# step: Step command received
# pa14: CHGRST (pin 1 on old Sony drives), connected to PA14 (JTCK/SWCLK)
# delay-N: Automatically after N*0.5sec (0 <= N <= 15)
chgrst = step
##
## STARTUP / INITIALISATION
@ -111,7 +82,7 @@ ejected-on-startup = no
# Which image (or folder) is selected at startup?
# last: Last-selected item at power-off (recorded in IMAGE_A.CFG)
# static: Static path specified in INIT_A.CFG
# static: Static path specified in IMAGE_A.CFG
# init: First item in root folder
# Values: last | static | init
image-on-startup = last
@ -134,20 +105,6 @@ autoselect-file-secs = 2
# Values: 0 <= N <= 255
autoselect-folder-secs = 2
# Sorting of folder entries in native navigation mode.
# always: Always sort folder entries. Large folders may be truncated.
# never: Never sort folder entries, instead presenting them in FAT order.
# small: Only sort folders which are small enough to sort in full.
# Values: always | never | small
folder-sort = always
# Priority of files vs subfolders when sorting folder entries:
# folders: Folders listed before files
# files: Files listed before folders
# none: Files and folders are not differentiated
# Values: folders | files | none
sort-priority = folders
# Navigation mode for selecting images/slots
# native: Navigate through all valid images/dirs
# indexed: Navigate through DSKA0000, DSKA0001, ...
@ -162,50 +119,33 @@ nav-loop = yes
# B1 | B2 | Both
# zero: Prev | Next | Slot 0
# eject: Prev | Next | Eject/Insert
# htu: +10 | +1 | +100
# rotary: Up-dir | Select/Eject/Insert | -
# rotary-fast: Prev | Next | Up-dir [Prev/Next are accelerated]
# reverse: Reverse sense of B1 and B2
# Multiple values can be separated by commas, eg twobutton-action=eject,reverse
twobutton-action = zero
# Input sensor type at the rotary-encoder inputs (pins PC10 and PC11):
# [full | half | quarter]:
# Rotary encoder, identified by fraction of a Gray-code cycle performed
# per detent/click. If default value (full) requires multiple
# clicks/detents to move position then change to half (if 2 clicks
# per move) or quarter (if 4 clicks).
# [trackball]:
# Blackberry-style trackball (eg. using Hall-effect sensors).
# [buttons]:
# Push-to-ground Prev/Next buttons.
# [reverse]:
# If the input is working in reverse, use this option to swap directions.
# [v2]:
# Use the rotary encoder logic from FlashFloppy v2.x. Use this if the
# v3 logic is too strict and results in no, or missing, movements.
# Type of rotary encoder connected to pins PC10 and PC11, identified by
# fraction of a Gray-code cycle performed per detent/click.
# If default value ('full') requires multiple clicks/detents to move position
# then change to 'half' (if 2 clicks per move) or 'quarter' (if 4 clicks).
# If the encoder works in reverse, use option 'reverse' to swap directions.
# Multiple values can be separated by commas, eg rotary=quarter,reverse
# Values: none | quarter | half | full | trackball | buttons | reverse | v2
# Values: none | quarter | half | full | reverse
rotary = full
# Prefix for image names in indexed navigation mode. String can be empty ("").
indexed-prefix = "DSKA"
##
## DISPLAY
# Display Type.
# Display Type: <type>[-rotate][-narrow][-sh1106]
# auto: Auto-detect (7-seg LED, LCD, OLED)
# lcd-CCxRR: CCxRR backlit LCD with I2C backpack (16<=CC<=40, 02<=RR<=04)
# lcd-NNx02: NNx2 backlit LCD with I2C backpack (16 <= NN <= 40)
# oled-128xNN: 128xNN I2C OLED (NN = 32 | 64)
# -rotate: OLED view is rotated 180 degrees
# -hflip: OLED view is flipped horizontally
# -narrow[er]: OLED view is restricted to Gotek display cutout
# (-narrow: 18 chars; -narrower: 16 chars)
# -inverse: Inverse/reverse video (black text on white background)
# -ztech: ZHONGJY_TECH 2.23" 128x32 SSD1305 OLED display
# -slow: Run I2C bus slower (use this if OLED regularly blanks/corrupts)
# Values: auto | lcd-CCxRR | oled-128xNN[-rotate][-narrow[er]]...
# -sh1106: OLED controller is SH1106, not SSD1306
# Values: auto | lcd-NNx02 | oled-128xNN[-rotate][-narrow[er]][-sh1106]
display-type = auto
# OLED Font. Narrow and wide options.
@ -219,34 +159,13 @@ oled-font = 6x13
# Values: 0 <= N <= 255
oled-contrast = 143
# Text height and arrangement on LCD/OLED and on OSD, respectively.
# Comma-separated list, one entry per display row, top down.
# Each list item is a digit plus optional height specifier: [0-7][d]
# content-row: 0-3 = specified content, 7 = blank
# 0: Current image name
# 1: Status
# 2: Image/Volume info
# 3: Current subfolder name
# height-specifier: d = double height (32px, OLED only; ignored for LCD)
# Default depends on display, eg.: oled-128x32 -> 0,1 ; oled-128x64 -> 3,0d,1
# Values: [0-7][d] | default
display-order = default
osd-display-order = default
# OSD text columns. This is currently respected only when no LCD/OLED is found.
# Values: 16 <= N <= 40
osd-columns = 40
# Turn an LCD or OLED display off after N seconds of inactivity
# N=0: always off; N=255: always on
# Values: 0 <= N <= 255
display-off-secs = 60
# Switch on LCD/OLED display when there is drive activity?
# yes: Trigger on track changes and disk writes
# sel: Trigger on drive select
# no: No automatic trigger
# Values: yes | sel | no
# Automatically switch LCD/OLED display on when there is drive activity?
# Values: yes | no
display-on-activity = yes
# LCD/OLED long filename scroll rate in milliseconds per update
@ -273,14 +192,6 @@ nav-scroll-pause = 300
# Values: 0 <= N <= 20
step-volume = 10
# Speaker volume for insert, eject, and slot-number notifications.
# Slot number is indicated by a sequence of beeps when an image is mounted
# iff "slotnr" is specified. The slot number is then notified by a sequence of
# long beeps (each counting +5), followed by a sequence of short beeps
# (each counting +1).
# Values: N[,slotnr] (0 <= N <= 15)
notify-volume = 0
# Report the specified version number to host software
# Values: <quoted-string> ("" means report real version)
# eg. da-report-version = "v3.0.0.0"

View file

@ -1,18 +0,0 @@
## IMG.CFG for Bung Multi Game Doctor (MGD) 2.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'mgd2' to the square-bracketed tags
# to limit matches to filenames of the form *.mgd2.{img,ima,dsk}
# Images are 1756kB exactly.
[::1798144]
cyls = 80
heads = 2
tracks = 0
secs = 18
bps = 512
tracks = 1-79
secs = 11
bps = 1024
gap3 = 30

View file

@ -1,170 +0,0 @@
## IMG.CFG: FlashFloppy Geometry Configuration File for Raw IMG Images
## For CompuPro 8-16 8" Floppy disks.
# Tested on a CompuPro 8-16 System using the 50-to-34 pin adapter
# board available here: https://gitlab.com/NF6X_Retrocomputing/fd50to34
#
# Make sure to set the jumpers on the fd50to34:
# * 2SIDE - Install if emulated floppy disk is double-sided.
# * MTRON - Install
#
# In FF.CFG, set interface=shugart
#
# Supports tagged IMG/IMA raw image files with self-identifying geometry.
# If you wish to use this feature, your IMG.CFG must be placed in the
# root folder or FF/ subfolder of your USB drive.
# NOTE: If FF/ exists, IMG.CFG must reside there, not the root folder.
# A badly-defined section (eg. undefined mandatory parameters) may result in
# error 31 (Bad Image).
####################################################################
## TAG in square brackets.
## Format: [<tagname>][::<filesize>]
## Matching Rules:
## 1. <tagname> matches images of the form *.<tagname>.{img,ima,dsk}
## 2. Missing (empty) tagname matches any *.{img,ima,dsk} which is untagged
## or does not match any other defined tag.
## 3. Tagnames and their matches are NOT case sensitive.
## 4. <filesize>, if specified, must exactly match the image filesize.
## 5. If an image matches no tag, FlashFloppy uses normal geometry
## auto-detection based on the host= setting in FF.CFG.
####################################################################
# Definition for standard CP/M 8" SS/DD.
#
# CP/M 8" SS/SD format is single-density (FM) with 26 128-byte
# sectors on all cylinders.
[::256256]
cyls = 77
heads = 1
rpm = 360
gap3 = 42
interleave = 1
bps = 128 ## 128-byte sectors
secs = 26
mode = fm
id = 1
####################################################################
# Definition for CompuPro 8" SS/DD.
#
# CP/M 8" SS/DD format is double-density but with a single-density
# (FM) cylinder 0.
[::625920]
cyls = 77
heads = 1
interleave = 1
rpm = 360
gap3 = 42
tracks = 0 ## Boot cylinder, head 0
bps = 128 ## Cylinder 0 has 128-byte sectors
secs = 26
mode = fm
id = 1
tracks = 1-76 ## All other cylinders
bps = 1024
secs = 8
mode = mfm
id = 1
####################################################################
# Definition for CompuPro 8" DS/SD.
#
# CP/M 8" DS/SD format is single density, 128-byte sectors.
[::512512]
cyls = 77
heads = 2
interleave = 1
rpm = 360
gap3 = 42
bps = 128
secs = 26
mode = fm
id = 1
####################################################################
# Definition for CompuPro 8" DS/DD 1024-byte sectors.
#
# CP/M 8" DS/DD format is double-density but with a single-density
# (FM) track 0.
[::1256704]
cyls = 77
heads = 2
interleave = 1
rpm = 360
gap3 = 42
tracks = 0.0 ## Boot cylinder, head 0
bps = 128 ## Cylinder 0, head 0 has 128-byte sectors
secs = 26
mode = fm
id = 1
tracks = 0.1 ## Boot cylinder, head 1
bps = 1024 ## Cylinder 0, head 1 has 1024-byte sectors
secs = 8
mode = mfm
id = 1
tracks = 1-76 ## All other cylinders
bps = 1024
secs = 8
mode = mfm
id = 1
####################################################################
# Definition for CompuPro 8" DS/DD 512-byte sectors.
#
# CP/M 8" DS/DD format is double-density but with a single-density
# (FM) track 0.
[::1178368]
cyls = 77
heads = 2
interleave = 1
rpm = 360
gap3 = 42
tracks = 0.0 ## Boot cylinder, head 0
bps = 128 ## Cylinder 0, head 0 has 128-byte sectors
secs = 26
mode = fm
id = 1
tracks = 0.1 ## Boot cylinder, head 1
bps = 512 ## Cylinder 0, head 1 has 512-byte sectors
secs = 15
mode = mfm
id = 1
tracks = 1-76 ## All other cylinders
bps = 512
secs = 15
mode = mfm
id = 1
####################################################################
# Definition for CompuPro 8" DS/DD 256-byte sectors.
#
# CP/M 8" DS/DD format is double-density but with a single-density
# (FM) track 0.
[::1021696]
cyls = 77
heads = 2
interleave = 1
rpm = 360
gap3 = 42
secs = 26
tracks = 0.0 ## Boot cylinder, head 0
bps = 128 ## Cylinder 0, head 0 has 128-byte sectors
mode = fm
id = 1
tracks = 0.1 ## Boot cylinder, head 1
bps = 256 ## Cylinder 0, head 1 has 256-byte sectors
secs = 26
mode = mfm
id = 1
tracks = 1-76 ## All other cylinders
bps = 256
secs = 26
mode = mfm
id = 1

View file

@ -1,16 +0,0 @@
## IMG.CFG for Dynacord ADS hosts.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'dyna' to the square-bracketed tags
# to limit matches to filenames of the form *.dyna.{img,ima,dsk}
[::1638400]
cyls = 80
heads = 2
bps = 512
secs = 20
interleave = 2
tracks = 0-79.0 ## Head 0
id = 1
tracks = 0-79.1 ## Head 1
id = 21 # Follows on from head 0 (1..20 -> 21..40)

View file

@ -1,39 +0,0 @@
# IMG.CFG for Ensoniq hosts
# 800kB and 1.6MB image types are also handled by FF.CFG: host=ensoniq
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'ensoniq' to the square-bracketed tags
# to limit matches to filenames of the form *.ensoniq.{img,ima,dsk}
# Ensoniq 800kB DSDD
# Also handled by FF.CFG: host=ensoniq
[::819200]
cyls = 80
heads = 2
secs = 10
bps = 512
gap3 = 30
id = 0
rate = 250
# Ensoniq 1.6MB DSHD
# Also handled by FF.CFG: host=ensoniq
[::1638400]
cyls = 80
heads = 2
secs = 20
bps = 512
gap3 = 40
id = 0
rate = 500
# Ensoniq Mirage 440kB SSDD
# Mixed sector sizes *NOT* handled by FF.CFG: host=ensoniq
[::450560]
cyls = 80
heads = 1
secs = 6
bps = 1024,1024,1024,1024,1024,512
id = 0
rate = 250

View file

@ -1,17 +0,0 @@
## IMG.CFG for machines produced by GRiD Systems Corp.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'flex' to the square-bracketed tags
# to limit matches to filenames of the form *.flex.{img,ima,dsk}
# 360k 40-cylinder DS/DD format used by GRiD Compass
[::368640]
cyls = 40
heads = 2
bps = 512
secs = 9
mode = mfm
interleave = 5
id = 1
tracks = 0-39.1
id = 10

View file

@ -1,40 +0,0 @@
## IMG.CFG for Kaypro systems.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'kp' to the square-bracketed tags
# to limit matches to filenames of the form *.kp.{img,ima,dsk}
# 200kB: SSDD, 40 cyl
[::204800]
cyls = 40
heads = 1
secs = 10
bps = 512
interleave = 3
id = 0
# 400kB: DSDD, 40 cyl
[::409600]
cyls = 40
heads = 2
secs = 10
bps = 512
interleave = 3
h = 0
tracks = 0-39.0
id = 0
tracks = 0-39.1
id = 10
# 800kB: DSDD, 80 cyl
[::819200]
cyls = 80
heads = 2
secs = 10
bps = 512
interleave = 3
h = 0
tracks = 0-79.0
id = 0
tracks = 0-79.1
id = 10

View file

@ -1,40 +0,0 @@
## IMG.CFG for Osborne systems.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'occ1' to the square-bracketed tags
# to limit matches to filenames of the form *.occ1.{img,ima,dsk}
# Osborne 1 OCC1/1A (for units without double density upgrade fitted)
# SSSD 100Kb
[::102400]
cyls = 40
heads = 1
secs = 10
bps = 256
cskew = 2
mode = fm
iam = no
# Osborne Executive OCC2 (also OCC1/1A with double density upgrade fitted)
# SSDD 200Kb
[::204800]
cyls = 40
heads = 1
secs = 5
bps = 1024
mode = mfm
iam = yes
# Osborne Vixen OCC4 (also Executive OCC2 with double sided upgrade fitted)
# DSDD 400Kb
# Note: Multiple sizes for OCC4. Covered here with a default rule but could
# instead explicitly handle the following sizes if the square-bracket syntax
# is ever extended to support it: 409600, 409728, 409856, 419840
[]
cyls = 40
heads = 2
secs = 5
bps = 1024
cskew = 2
mode = mfm
iam = yes

View file

@ -1,60 +0,0 @@
## IMG.CFG for faster loading of Roland OS and System disks.
## Some Roland disks have 'sector interleave' and if this is missing (as in
## default 720kB track configuration) the OS and System Utilities can load
## approximately 5x slower than expected. The configurations below fix this.
# NOTES:
#
# 1. OS and System images must be named as described below.
#
# 2. By default 'os' and 'sys' tags apply sector interleave to all tracks.
# Some disks (eg S-330 OS disk) contain sample data with no interleave:
# They will load 2x slower than expected. If this concerns you, adjust the
# 'track=' line to cover only the tracks requiring interleave (eg. '0-8').
#
# 3. You can copy and paste the sections below to create further tags as
# needed for your specific set of OS and System disks.
# Matches 720kB images named *.os.{img,ima,dsk}.
[os::737280]
cyls = 80
heads = 2
secs = 9
bps = 512
tracks = 0-79 # This line can be adjusted
interleave = 2
hskew = 1
cskew = 2
# Matches 720kB images named *.sys.{img,ima,dsk}.
[sys::737280]
cyls = 80
heads = 2
secs = 9
bps = 512
tracks = 0-79 # This line can be adjusted
interleave = 2
hskew = 1
cskew = 2
# Matches 720kB images named *.mc.{img,ima,dsk}.
# This higher level of interleave is found on all disks for the
# Roland MC-300, MC-500 and MC-50.
[mc::737280]
cyls = 80
heads = 2
secs = 9
bps = 512
tracks = 0-79
interleave = 4
# Roland 1.44MB format may apply sector skew.
# This is as seen on a Roland MT-200.
[::1474560]
cyls = 80
heads = 2
secs = 18
bps = 512
hskew = 3
cskew = 6

View file

@ -1,14 +0,0 @@
# IMG.CFG for Sequential Circuits hosts
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'sci' to the square-bracketed tags
# to limit matches to filenames of the form *.sci.{img,ima,dsk}
# Sequential Circuits Prophet 840kB DSDD
[::860160]
cyls = 80
heads = 2
secs = 6
bps = 1024,1024,1024,1024,1024,256
id = 0
rate = 250

View file

@ -1,13 +0,0 @@
## IMG.CFG for Sinclair QL ED Disks (3.2MB)
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'ql' to the square-bracketed tags
# to limit matches to filenames of the form *.ql.{img,ima,dsk}
# Images are 3200kB exactly.
[::3276800]
cyls = 80
heads = 2
secs = 10
bps = 2048

View file

@ -1,24 +0,0 @@
The Clive Drive controller has a 16-pin drive interface. Pins 3-12
inclusive correspond to the usual 10-pin QD interface. For reference,
see the Clive Drive schematic at:
https://speccy4ever.speccy.org/rom/clive/Clive%20Drive.pdf
Clive Controller QDD Gotek
1---------NC
2---------NC
3---------WRITE PROTECT (WRPR) 1 28
4---------WRITE DATA (WRDT) 2 22
5---------WRITE GATE 1 (WRGT1) 3 24
6---------MOTOR ON 1 (MTON1) 4 16
7---------READ DATA (RDDT) 5 30
8---------READY 6 34
9---------MEDIA SENSE (MDST) 7 2
10--------QD RESET (QDDRST) 8 20
11--------VCC +5V 9 +5v
12--------GND 10 GND
13--------MOTOR ON 2 (MTON2) NC NC
14--------WRITE GATE 2 (WRGT2) NC NC
15--------SEL IN (SELIN) NC NC
16--------NC

View file

@ -1,45 +0,0 @@
## IMG.CFG for the Sandy FDD2 interface.
# Sandy FDD2 is a clone of the FDC-1 by Technology Research Ltd.
# Using a 1771 controller chip, it supports single-density (FM) recording
# only, unlike the later Beta Disk interfaces.
# *.ss40.img: Single-sided 40 cylinders.
[ss40::102400]
cyls = 40
heads = 1
secs = 10
bps = 256
mode = fm
interleave = 2
# *.ss80.img: Single-sided 80 cylinders.
[ss80::204800]
cyls = 80
heads = 1
secs = 10
bps = 256
mode = fm
interleave = 2
# *.ds40.img: Double-sided 40 cylinders.
[ds40::204800]
cyls = 40
heads = 2
secs = 10
bps = 256
mode = fm
interleave = 2
tracks = 0-39.1
h = 0
# *.ds80.img: Double-sided 80 cylinders.
[ds80::409600]
cyls = 80
heads = 2
secs = 10
bps = 256
mode = fm
interleave = 2
tracks = 0-79.1
h = 0

View file

@ -1,68 +0,0 @@
## IMG.CFG for TSC Flex hosts.
# NOTE: The tags match on filesize alone. If you wish to define an explicit
# tagname match, you can for example add 'flex' to the square-bracketed tags
# to limit matches to filenames of the form *.flex.{img,ima,dsk}
# DS/DD with SD (FM) cylinder 0.
# Sector numbering and interleave is continuous across drive heads. Since
# there is no direct way to flag this, we implement it here by explicitly
# specifying head 1 track formats: with sector @id following on from head 0,
# and with @hskew shifting the first sector of side 1 the correct amount to
# simulate cross-track interleave.
[::733184]
cyls = 80
heads = 2
bps = 256 # All tracks have 256-byte sectors. Number of sectors varies.
iam = no
gap3 = 16
gap4a = 16
tracks = 0.0 ## Boot cylinder, head 0
secs = 10
mode = fm
interleave = 4
id = 1
h = 0
tracks = 0.1 ## Boot cylinder, head 1
secs = 10
mode = fm
interleave = 4
hskew = 1 # Simulates correct inter-track interleave
id = 11 # Follows on from head 0 (1..10 -> 11..20)
h = 0
tracks = 1-79.0 ## All other cylinders, head 0
secs = 18
mode = mfm
interleave = 6
id = 1
h = 1
tracks = 1-79.1 ## All other cylinders, head 1
secs = 18
mode = mfm
interleave = 6
hskew = 5 # Simulates correct inter-track interleave
id = 19 # Follows on from head 0 (1..18 -> 19..36)
h = 1
# SS/DD with SD (FM) cylinder 0.
# Definition is a simplified version of the DS/DD format.
[::366592]
cyls = 80
heads = 1
bps = 256
iam = no
gap3 = 16
gap4a = 16
id = 1
tracks = 0.0
secs = 10
mode = fm
interleave = 4
h = 0
tracks = 1-79.0
secs = 18
mode = mfm
interleave = 6
h = 1

View file

@ -1,172 +0,0 @@
## IMG.CFG: Example FlashFloppy Geometry Configuration File for Raw IMG Images
# Supports tagged IMG/IMA raw image files with self-identifying geometry.
# If you wish to use this feature, your IMG.CFG must be placed in the
# root folder or FF/ subfolder of your USB drive.
# NOTE: If FF/ exists, IMG.CFG must reside there, not the root folder.
# A badly-defined section (eg. undefined mandatory parameters) may result in
# error 31 (Bad Image).
####################################################################
## TAG in square brackets.
## Format: [<tagname>][::<filesize>]
## Matching Rules:
## 1. <tagname> matches images of the form *.<tagname>.{img,ima,dsk}
## 2. Missing (empty) tagname matches any *.{img,ima,dsk} which is untagged
## or does not match any other defined tag.
## 3. Tagnames and their matches are NOT case sensitive.
## 4. <filesize>, if specified, must exactly match the image filesize.
## 5. If an image matches no tag, FlashFloppy uses normal geometry
## auto-detection based on the host= setting in FF.CFG.
# [dsdd80::737280] matches images with names of the form *.dsdd80.{img,ima,dsk}
# and with size exactly 720kB (737280 bytes).
[dsdd80::737280]
## DISK-SCOPE PARAMETERS
# Apply to the whole disk image. Cannot appear in a @tracks sub-section.
# Mandatory: Number of cylinders (1-255).
cyls = 80
# Mandatory: Number of heads (1-2).
heads = 2
# Number of drive-head steps between cylinders. Default is 1.
# step = 1
# Image file track layout. Default is "interleaved".
# Comma-separated values:
# sequential: Sequential cylinder ordering: all side 0, then side 1.
# interleaved: Interleaved cylinder ordering: c0s0, c0s1, c1s0, c1s1, ...
# reverse-sideN: Side-N cylinders are ordered from high to low (N=0,1).
# sides-swapped: Sides 0 and 1 ordering is swapped in the image file.
# eg. "sequential,reverse-side1"
# file-layout = interleaved
## TRACK-SCOPE PARAMETERS
# These can vary across tracks. By default they apply to all tracks unless
# preceded by a @tracks declaration.
# tracks = <track-list>
# Specify the tracks that the following track-scope parameters applies to.
# Format:
# track-list ::= <track-range>[,<track-list>]
# track-range ::= <cylinder>[.<head>] | <cylinder>-<cylinder>[.<head>]
# cylinder ::= [0-9][0-9]*
# head ::= 0|1
# If no head is specified in a track-range, then all heads are assumed.
# Examples:
# "0-23.1,45.0" specifies head 1 of cyls 0-23 and head 0 of cyl 45.
# "27-33" specifies all heads of cyls 27-33.
# Number of sectors per track (0-256). Default is 0.
secs = 9
# Bytes per sector (128, 256, 512, 1024, 2048, 4096, 8192).
# Mandatory if @secs is non-zero.
bps = 512
# Alternative form in which bytes per sector is specified per sector.
# The list is comma separated; no white space allowed.
# bps = 512,512,512,512,512,512,512,512,256
# Bytes per sector within the IMG file. Smaller sectors will be padded.
# The default is 0: Sectors occupy precisely their data size; No padding.
# Supported values: 0, 128, 256, 512, 1024, 2048, 4096, 8192.
# img_bps = 0
# ID of first sector on each track (0-255). Default is 1.
# Numbers may be expressed in hexadecimal with 0x prefix (eg. 0xab).
# id = 1
# Head number for all sectors on this track (auto|0|1). Default is auto.
# auto = use physical drive head number
# h = auto
# Recording mode (fm | mfm). Default is mfm.
# mode = mfm
# Sector interleave. Default is 1:1 (no interleave).
# interleave = 1
# Sector skew per cylinders. Default is 0 (no skew).
# cskew = 0
# Sector skew per head. Default is 0 (no skew).
# hskew = 0
# Rotational RPM. Default is 300.
# rpm = 300
# Post-ID Gap (auto|0-255). Default is auto.
# auto = based on recording mode and sector size.
# gap2 = auto
# Post-Data Gap (auto|0-255). Default is auto.
# auto = based on recording mode and sector size.
# gap3 = auto
# Post-Index Gap (auto|0-255). Default is auto.
# auto = based on recording mode and sector size.
# gap4a = auto
# Index Address Mark (yes | no). Default is yes.
# iam = yes
# Data rate in kHz (kbit/s) (eg. MFM DD = 250). Default is 0.
# 0 = based on recording mode and size of track.
# rate = 0
####################################################################
# An example definition for a Kaypro DS/DD 40-track image.
[kaypro-dsdd40]
cyls = 40
heads = 2
interleave = 3
secs = 10
bps = 512
tracks = 0-39.0
id = 0 # Side 0, sector IDs 0..9
tracks = 0-39.1
id = 10 # Side 1, sector IDs 10..19
####################################################################
# An example definition for TSC Flex.
#
# Flex format is double-density but with single-density (FM) cylinder 0.
# Sector numbering and interleave is continuous across drive heads. Since
# there is no direct way to flag this, we implement it here by explicitly
# specifying head 1 track formats: with sector @id following on from head 0,
# and with @hskew shifting the first sector of side 1 the correct amount to
# simulate cross-track interleave.
[flex::733184]
cyls = 80
heads = 2
bps = 256 # All tracks have 256-byte sectors. Number of sectors varies.
tracks = 0.0 ## Boot cylinder, head 0
secs = 10
mode = fm
interleave = 4
id = 1
tracks = 0.1 ## Boot cylinder, head 1
secs = 10
mode = fm
interleave = 4
hskew = 1 # Simulates correct inter-track interleave
id = 11 # Follows on from head 0 (1..10)
tracks = 1-79.0 ## All other cylinders, head 0
secs = 18
mode = mfm
interleave = 6
id = 1
tracks = 1-79.1 ## All other cylinders, head 1
secs = 18
mode = mfm
interleave = 6
hskew = 5 # Simulates correct inter-track interleave
id = 19 # Follows on from head 0 (1..18)

View file

@ -1,44 +0,0 @@
/*
* cache.h
*
* In-memory data cache.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#if !defined(BOOTLOADER)
/* Use memory range (@start,@end) to cache data items of size @item_sz. */
struct cache *cache_init(void *start, void *end, unsigned int item_sz);
/* Look up item @id in the cache. Return a pointer to cached data, or NULL. */
const void *cache_lookup(struct cache *c, uint32_t id);
/* Update item @id with data @dat. Inserts the item if not present.*/
void cache_update(struct cache *c, uint32_t id, const void *dat);
/* Update @N items (@id..@id+@N-1) with data @dat. Calls cache_update(). */
void cache_update_N(struct cache *c, uint32_t id,
const void *dat, unsigned int N);
#else
#define cache_init(a,b,c) NULL
#define cache_lookup(a,b) NULL
#define cache_update(a,b,c) ((void)0)
#define cache_update_N(a,b,c,d) ((void)0)
#endif
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -21,11 +21,9 @@ struct opts {
};
int get_next_opt(struct opts *opts);
#define OPT_eof -1
#define OPT_section -2
/* FF.CFG options structure. */
struct packed ff_cfg {
struct __packed ff_cfg {
/* Bump version for every incompatible change to structure layout.
* No need to bump for new fields appended to this structure. */
#define FFCFG_VERSION 2
@ -41,10 +39,7 @@ struct packed ff_cfg {
uint8_t autoselect_folder_secs;
bool_t nav_loop; /* Wrap slot number at 0 and max? */
uint8_t display_off_secs;
#define DISPON_no 0
#define DISPON_yes 1
#define DISPON_sel 2
uint8_t display_on_activity;
bool_t display_on_activity; /* Display on when there is drive activity? */
uint16_t display_scroll_rate;
#define FONT_6x13 7
#define FONT_8x16 8
@ -61,8 +56,7 @@ struct packed ff_cfg {
#define TWOBUTTON_eject 1
#define TWOBUTTON_rotary 2
#define TWOBUTTON_rotary_fast 3
#define TWOBUTTON_htu 4
#define TWOBUTTON_mask 7
#define TWOBUTTON_mask 3
#define TWOBUTTON_reverse (1u<<7)
uint8_t twobutton_action;
#define NAVMODE_default 0
@ -86,37 +80,26 @@ struct packed ff_cfg {
#define HOST_dec 11
#define HOST_tandy_coco 12
#define HOST_fluke 13
#define HOST_kaypro 14
#define HOST_nascom 15
#define HOST_casio 16
#define HOST_ibm_3174 17
uint8_t host;
/* Bitfields within display_type field. */
#define DISPLAY_auto 0
#define DISPLAY_lcd (1<<0)
#define DISPLAY_oled (1<<1)
/* Only if DISPLAY_oled: */
#define DISPLAY_narrower (1<<0)
#define DISPLAY_rotate (1<<2)
#define DISPLAY_narrow (1<<3)
#define DISPLAY_ztech (1<<4)
#define DISPLAY_oled_64 (1<<5)
#define DISPLAY_inverse (1<<6)
#define DISPLAY_slow (1<<7)
#define DISPLAY_hflip (1<<8)
/* Only if DISPLAY_lcd: */
#define _DISPLAY_lcd_columns 5
#define DISPLAY_narrower (1<<0) /* only if DISPLAY_oled */
#define DISPLAY_rotate (1<<2) /* only if DISPLAY_oled */
#define DISPLAY_narrow (1<<3) /* only if DISPLAY_oled */
#define DISPLAY_sh1106 (1<<4) /* only if DISPLAY_oled */
#define DISPLAY_oled_64 (1<<5) /* only if DISPLAY_oled */
#define _DISPLAY_lcd_columns 5 /* only if DISPLAY_lcd */
#define DISPLAY_lcd_columns(x) ((x)<<_DISPLAY_lcd_columns)
#define _DISPLAY_lcd_rows 11
#define DISPLAY_lcd_rows(x) ((x)<<_DISPLAY_lcd_rows)
uint16_t display_type;
#define ROT_none 0
#define ROT_full 1
#define ROT_half 3
#define ROT_quarter 2
#define ROT_trackball 4
#define ROT_buttons 5
#define ROT_typemask 15
#define ROT_v2 (1u<<6)
#define ROT_none 0
#define ROT_full 1
#define ROT_half 3
#define ROT_quarter 2
#define ROT_reverse (1u<<7)
uint8_t rotary;
bool_t write_protect;
@ -139,43 +122,12 @@ struct packed ff_cfg {
uint8_t pin02, pin34;
uint8_t head_settle_ms;
uint8_t oled_contrast;
char indexed_prefix[8];
uint8_t _unused; /* never been used */
#define SORT_never 0
#define SORT_always 1
#define SORT_small 2
uint8_t folder_sort;
#define MOTOR_ignore 0xff
uint8_t motor_delay; /* / 10ms */
#define SORTPRI_folders 0
#define SORTPRI_files 1
#define SORTPRI_none 2
uint8_t sort_priority;
#define CHGRST_step 0xff
#define CHGRST_pa14 0x8e
#define CHGRST_delay(x) (x)
uint8_t chgrst;
#define DORD_default 0xffff
#define DORD_shift 4
#define DORD_row 7
#define DORD_double 8
uint16_t display_order;
#define WDRAIN_instant 0
#define WDRAIN_realtime 1
#define WDRAIN_eot 2
uint8_t write_drain;
uint8_t max_cyl;
uint16_t osd_display_order;
uint8_t osd_columns;
#define NOTIFY_volume_mask 15
#define NOTIFY_slotnr (1<<4)
uint8_t notify_volume;
};
extern struct ff_cfg ff_cfg;
extern const struct ff_cfg dfl_ff_cfg;
void flash_ff_cfg_update(void *scratch);
void flash_ff_cfg_update(void);
void flash_ff_cfg_erase(void);
void flash_ff_cfg_read(void);

View file

@ -14,7 +14,7 @@
#define DA_DD_MFM_CYL (DA_FIRST_CYL + 1)
/* Direct-Access Mode: Returned in sector 0 of direct-access track. */
struct packed da_status_sector {
struct __packed da_status_sector {
char sig[8];
char fw_ver[12];
uint32_t lba_base;
@ -32,7 +32,7 @@ struct packed da_status_sector {
};
/* Direct-Access Mode: Sent to us in sector 0 of direct-access track. */
struct packed da_cmd_sector {
struct __packed da_cmd_sector {
char sig[8];
uint8_t cmd;
uint8_t param[8];

View file

@ -13,28 +13,16 @@
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <limits.h>
#include "types.h"
#include "mcu/common_regs.h"
#include "mcu/common.h"
#if MCU == STM32F105
#include "mcu/stm32f105_regs.h"
#include "mcu/at32f415_regs.h"
#include "mcu/stm32f105.h"
#elif MCU == AT32F435
#include "mcu/at32f435_regs.h"
#include "mcu/at32f435.h"
#endif
#include "stm32f10x_regs.h"
#include "stm32f10x.h"
#include "intrinsics.h"
#include "time.h"
#include "../src/fatfs/ff.h"
#include "util.h"
#include "list.h"
#include "cache.h"
#include "da.h"
#include "hxc.h"
#include "util.h"
#include "cancellation.h"
#include "spi.h"
#include "timer.h"

View file

@ -9,25 +9,11 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#define SAMPLECLK_MHZ 72
#define sampleclk_ns(x) (((x) * SAMPLECLK_MHZ) / 1000)
#define sampleclk_us(x) ((x) * SAMPLECLK_MHZ)
#define sampleclk_ms(x) ((x) * SAMPLECLK_MHZ * 1000)
#define sampleclk_stk(x) ((x) * (SAMPLECLK_MHZ / STK_MHZ))
#define stk_sampleclk(x) ((x) / (SAMPLECLK_MHZ / STK_MHZ))
#ifdef QUICKDISK
#define is_quickdisk TRUE
#else
#define is_quickdisk FALSE
#endif
#define FINTF_SHUGART 0
#define FINTF_IBMPC 1
#define FINTF_IBMPC_HDOUT 2
#define FINTF_JPPC_HDOUT 3
#define FINTF_AKAI_S950 3
#define FINTF_AMIGA 4
#define FINTF_JPPC 5
#define outp_dskchg 0
#define outp_index 1
@ -38,87 +24,44 @@
#define outp_nr 6
#define outp_unused outp_nr
#define verbose_image_log FALSE
struct adf_image {
uint32_t trk_off;
uint32_t sec_idx;
uint16_t trk_pos, trk_len;
int32_t decode_pos;
uint32_t pre_idx_gap_bc;
uint32_t nr_secs;
uint32_t written_secs;
uint8_t sec_map[2][22];
};
struct hfe_image {
uint16_t tlut_base;
uint16_t trk_off;
uint16_t trk_pos, trk_len;
bool_t is_v3, double_step;
bool_t is_v3;
uint8_t batch_secs;
struct {
uint16_t start;
bool_t wrapped;
} write;
struct {
uint16_t off, len;
bool_t dirty;
} write_batch;
};
struct qd_image {
uint16_t tb;
uint32_t trk_off;
uint32_t trk_pos, trk_len;
uint32_t win_start, win_end;
struct {
uint32_t start;
bool_t wrapped;
} write;
struct {
uint32_t off, len;
bool_t dirty;
} write_batch;
};
struct raw_sec {
uint8_t r;
uint8_t n; /* 3 bits */
};
struct raw_trk {
uint16_t nr_sectors;
uint16_t sec_off;
uint16_t data_rate;
uint16_t rpm;
uint16_t img_bps; /* could squeeze this field into uint8_t or bitfield */
int16_t gap_2, gap_3, gap_4a;
uint8_t interleave, cskew, hskew;
uint8_t has_iam:1, is_fm:1, invert_data:1;
#define RAW_TRK_HEAD(h) ((h)+1)
uint8_t head:2;
};
struct img_image {
uint32_t trk_off, base_off;
uint16_t trk_sec, rd_sec_pos;
uint16_t rpm;
int32_t decode_pos;
uint16_t decode_data_pos, crc;
uint8_t layout; /* LAYOUT_* */
bool_t has_iam;
uint8_t gap_2, gap_3, gap_4a;
uint8_t post_crc_syncs;
int16_t write_sector;
uint8_t *sec_map, *trk_map;
struct raw_trk *trk, *trk_info;
struct raw_sec *sec_info, *sec_info_base;
/* If not NULL, replaces the default method for finding sector data.
* Sector data is at trk_off + file_sec_offsets[i]. */
uint32_t *file_sec_offsets;
/* Delay start of track this many bitcells past index. */
uint32_t track_delay_bc;
uint16_t gap_4;
int8_t write_sector;
uint8_t sec_base[2], sec_map[64];
uint8_t nr_sectors, sec_no;
uint8_t interleave:4, skew:4;
bool_t skew_cyls_only;
uint16_t data_rate, gap_4;
uint32_t idx_sz, idam_sz;
uint16_t dam_sz_pre, dam_sz_post;
void *heap_bottom;
};
struct dsk_image {
@ -140,7 +83,6 @@ struct directaccess {
int32_t decode_pos;
uint16_t trk_sec;
uint16_t idx_sz, idam_sz, dam_sz;
bool_t lba_set;
};
struct image_buf {
@ -161,18 +103,13 @@ struct image_bufs {
};
struct image {
/* Handler for currently-selected type of disk image. */
const struct image_handler *disk_handler;
/* Handler for current track. May differ from the primary disk handler. */
const struct image_handler *track_handler;
const struct image_handler *handler;
/* FatFS. */
FIL fp;
/* Info about image as a whole. */
uint8_t nr_cyls, nr_sides;
uint8_t step;
/* Data buffers. */
struct image_bufs bufs;
@ -187,7 +124,7 @@ struct image {
/* Info about current track. */
uint16_t cur_track;
uint16_t write_bc_ticks; /* SAMPLECLK ticks per bitcell in write stream */
uint16_t write_bc_ticks; /* Nr SYSCLK ticks per bitcell in write stream */
uint32_t ticks_per_cell; /* Nr 'ticks' per bitcell in read stream. */
uint32_t tracklen_bc, cur_bc; /* Track length and cursor, in bitcells */
uint32_t tracklen_ticks; /* Timing of previous revolution, in 'ticks' */
@ -200,13 +137,12 @@ struct image {
union {
struct adf_image adf;
struct hfe_image hfe;
struct qd_image qd;
struct img_image img;
struct dsk_image dsk;
struct directaccess da;
};
struct slot *slot;
const struct slot *slot;
};
static inline struct write *get_write(struct image *im, uint16_t idx)
@ -216,7 +152,7 @@ static inline struct write *get_write(struct image *im, uint16_t idx)
struct image_handler {
bool_t (*open)(struct image *im);
FSIZE_t (*extend)(struct image *im);
void (*extend)(struct image *im);
void (*setup_track)(
struct image *im, uint16_t track, uint32_t *start_pos);
bool_t (*read_track)(struct image *im);
@ -234,13 +170,13 @@ extern const struct image_type {
bool_t image_valid(FILINFO *fp);
/* Open specified image file on mass storage device. */
void image_open(struct image *im, struct slot *slot, DWORD *cltbl);
void image_open(struct image *im, const struct slot *slot);
/* Extend a trunated image file. */
void image_extend(struct image *im);
/* Seek to given track and start reading track data at specified rotational
* position (specified as number of SAMPLECLK ticks past the index mark).
* position (specified as number of SYSCLK ticks past the index mark).
*
* If start_pos is NULL then the caller is in write mode and thus is not
* interested in fetching data from a particular rotational position.
@ -260,18 +196,13 @@ uint16_t bc_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr);
* was completed for the write at the tail of the pipeline. */
bool_t image_write_track(struct image *im);
/* Rotational position of last-generated flux (SAMPLECLK ticks past index). */
/* Rotational position of last-generated flux (SYSCLK ticks past index). */
uint32_t image_ticks_since_index(struct image *im);
/* MFM conversion. */
extern const uint16_t mfmtab[];
static inline uint16_t bintomfm(uint8_t x) { return mfmtab[x]; }
uint8_t mfmtobin(uint16_t x);
void mfm_to_bin(const void *in, void *out, unsigned int nr);
void mfm_ring_to_bin(const uint16_t *ring, unsigned int mask,
unsigned int idx, void *out, unsigned int nr);
#define MFM_DAM_CRC 0xe295 /* 0xa1, 0xa1, 0xa1, 0xfb */
#define FM_DAM_CRC 0xbf84 /* 0xfb */
/* FM conversion. */
#define FM_SYNC_CLK 0xc7
@ -284,23 +215,9 @@ void floppy_insert(unsigned int unit, struct slot *slot);
void floppy_cancel(void);
bool_t floppy_handle(void); /* TRUE -> re-read config file */
void floppy_set_cyl(uint8_t unit, uint8_t cyl);
struct track_info {
uint8_t cyl, side:1, sel:1, writing:1, in_da_mode:1;
};
void floppy_get_track(struct track_info *ti);
void floppy_get_track(uint8_t *p_cyl, uint8_t *p_side, uint8_t *p_sel,
uint8_t *p_writing);
void floppy_set_fintf_mode(void);
void floppy_set_max_cyl(void);
static inline unsigned int im_nphys_cyls(struct image *im)
{
return min_t(unsigned int, im->nr_cyls * (im->step?:1), 255);
}
static inline bool_t in_da_mode(struct image *im, unsigned int cyl)
{
return cyl >= max_t(unsigned int, DA_FIRST_CYL, im_nphys_cyls(im));
}
extern uint32_t motor_chgrst_exti_mask;
void motor_chgrst_setup_exti(void);
/*
* Local variables:

View file

@ -19,7 +19,7 @@ void F_close(FIL *fp);
void F_read(FIL *fp, void *buff, UINT btr, UINT *br);
void F_write(FIL *fp, const void *buff, UINT btw, UINT *bw);
void F_sync(FIL *fp);
void F_lseek(FIL *fp, FSIZE_t ofs);
void F_lseek(FIL *fp, DWORD ofs);
void F_truncate(FIL *fp);
void F_opendir(DIR *dp, const TCHAR *path);
void F_closedir(DIR *dp);

View file

@ -10,7 +10,7 @@
*/
/* HXCSDFE.CFG file header. */
struct packed hxcsdfe_cfg {
struct __packed hxcsdfe_cfg {
char signature[16]; /* "HXCFECFGVx.y" */
uint8_t step_sound;
uint8_t ihm_sound;
@ -27,7 +27,7 @@ struct packed hxcsdfe_cfg {
uint8_t startup_mode;
uint8_t enable_drive_b;
uint8_t index_mode;
struct packed {
struct __packed {
uint8_t cfg_from_cfg;
uint8_t interfacemode;
uint8_t pin02_cfg;
@ -47,7 +47,7 @@ struct packed hxcsdfe_cfg {
#define HXCSTARTUP_ejected 0x10
/* HXCFECFGV1.x slots start at offset 0x400: */
struct packed v1_slot {
struct __packed v1_slot {
char name[12];
uint8_t attributes;
uint32_t firstCluster;
@ -56,7 +56,7 @@ struct packed v1_slot {
};
/* HXCFECFGV2.x slots start at sector offset 'slots_position': */
struct packed v2_slot {
struct __packed v2_slot {
char type[3];
uint8_t attributes;
uint32_t firstCluster;

View file

@ -13,16 +13,9 @@ struct exception_frame {
uint32_t r0, r1, r2, r3, r12, lr, pc, psr;
};
#define _STR(x) #x
#define STR(x) _STR(x)
/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(cond) ({ _Static_assert(!(cond), "!(" #cond ")"); })
#define aligned(x) __attribute__((aligned(x)))
#define packed __attribute((packed))
#define __aligned(x) __attribute__((aligned(x)))
#define __packed __attribute((packed))
#define always_inline __inline__ __attribute__((always_inline))
#define noinline __attribute__((noinline))
#define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)
@ -74,14 +67,6 @@ struct exception_frame {
* confirmed on Cortex-M3. */
#define IRQ_restore(oldpri) write_special(basepri, (oldpri))
#define __DEFINE_IRQ(nr, name) \
void IRQ_##nr (void) __attribute__((alias(name)))
#define _DEFINE_IRQ(nr, name) __DEFINE_IRQ(nr, name)
#define DEFINE_IRQ(nr, name) _DEFINE_IRQ(nr, name)
/* Cortex initialisation */
void cortex_init(void);
static inline uint16_t _rev16(uint16_t x)
{
uint16_t result;

View file

@ -1,57 +0,0 @@
/*
* list.h
*
* Doubly linked list.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
struct list_head {
struct list_head *prev, *next;
};
static inline void list_init(struct list_head *head)
{
head->prev = head;
head->next = head;
}
static inline void list_insert_head(
struct list_head *head, struct list_head *ent)
{
ent->next = head->next;
ent->prev = head;
ent->next->prev = head->next = ent;
}
static inline void list_insert_tail(
struct list_head *head, struct list_head *ent)
{
ent->prev = head->prev;
ent->next = head;
ent->prev->next = head->prev = ent;
}
static inline void list_remove(struct list_head *ent)
{
ent->next->prev = ent->prev;
ent->prev->next = ent->next;
}
static inline bool_t list_is_empty(struct list_head *head)
{
return head->next == head;
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,34 +0,0 @@
/*
* at32f415_regs.h
*
* Extra registers and features of the AT32F415 that we use, over and above
* the baseline features of the STM32F105.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#define RCC_CFGR_PLLMUL_18 ((uint32_t)0x20040000)
#define RCC_CFGR_USBPSC_3 ((uint32_t)0x08400000)
#define RCC_PLL (&rcc->cfgr2)
#define RCC_PLL_PLLCFGEN (1u<<31)
#define RCC_PLL_FREF_MASK (7u<<24)
#define RCC_PLL_FREF_8M (2u<<24)
static volatile uint32_t * const RCC_MISC2 = (uint32_t *)(RCC_BASE + 0x54);
#define RCC_MISC2_AUTOSTEP_EN (3u<< 4)
#define TIM_CR1_PMEN (1u<<10)
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,80 +0,0 @@
/*
* at32f435.h
*
* Core and peripheral registers.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* C pointer types */
#define FLASH_BANK volatile struct flash_bank * const
#define SYSCFG volatile struct syscfg * const
#define DMAMUX volatile struct dmamux * const
/* C-accessible registers. */
static STK stk = (struct stk *)STK_BASE;
static SCB scb = (struct scb *)SCB_BASE;
static NVIC nvic = (struct nvic *)NVIC_BASE;
static DBG dbg = (struct dbg *)DBG_BASE;
static FLASH flash = (struct flash *)FLASH_BASE;
static PWR pwr = (struct pwr *)PWR_BASE;
static BKP bkp = (struct bkp *)BKP_BASE;
static RCC rcc = (struct rcc *)RCC_BASE;
static GPIO gpioa = (struct gpio *)GPIOA_BASE;
static GPIO gpiob = (struct gpio *)GPIOB_BASE;
static GPIO gpioc = (struct gpio *)GPIOC_BASE;
static GPIO gpiod = (struct gpio *)GPIOD_BASE;
static GPIO gpioe = (struct gpio *)GPIOE_BASE;
static GPIO gpiof = (struct gpio *)GPIOF_BASE;
static GPIO gpiog = (struct gpio *)GPIOG_BASE;
static GPIO gpioh = (struct gpio *)GPIOH_BASE;
static SYSCFG syscfg = (struct syscfg *)SYSCFG_BASE;
static EXTI exti = (struct exti *)EXTI_BASE;
static DMA dma1 = (struct dma *)DMA1_BASE;
static DMA dma2 = (struct dma *)DMA2_BASE;
static DMAMUX dmamux1 = (struct dmamux *)DMAMUX1_BASE;
static DMAMUX dmamux2 = (struct dmamux *)DMAMUX2_BASE;
static TIM tim1 = (struct tim *)TIM1_BASE;
static TIM tim2 = (struct tim *)TIM2_BASE;
static TIM tim3 = (struct tim *)TIM3_BASE;
static TIM tim4 = (struct tim *)TIM4_BASE;
static TIM tim5 = (struct tim *)TIM5_BASE;
static TIM tim6 = (struct tim *)TIM6_BASE;
static TIM tim7 = (struct tim *)TIM7_BASE;
static SPI spi1 = (struct spi *)SPI1_BASE;
static SPI spi2 = (struct spi *)SPI2_BASE;
static SPI spi3 = (struct spi *)SPI3_BASE;
static I2C i2c1 = (struct i2c *)I2C1_BASE;
static I2C i2c2 = (struct i2c *)I2C2_BASE;
static USART usart1 = (struct usart *)USART1_BASE;
static USART usart2 = (struct usart *)USART2_BASE;
static USART usart3 = (struct usart *)USART3_BASE;
static USB_OTG usb_otg = (struct usb_otg *)USB_OTG_BASE;
/* Clocks */
#define SYSCLK_MHZ 288
#define AHB_MHZ 288
#define APB1_MHZ 144
#define APB2_MHZ 144
/* GPIO */
void gpio_set_af(GPIO gpio, unsigned int pin, unsigned int af);
#define SOFTIRQ_0 85
#define SOFTIRQ_1 86
extern volatile uint32_t _reset_flag;
#define RESET_FLAG_BOOTLOADER 0xdeadbeefu
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,421 +0,0 @@
/*
* at32f435_regs.h
*
* Core and peripheral register definitions.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* Power control */
struct pwr {
uint32_t cr; /* 00: Power control */
uint32_t csr; /* 04: Power control/status */
uint32_t rsvd[2];
uint32_t ldoov; /* 10: LDO output voltage */
};
#define PWR_LDOOV_1V3 (1u<<0)
#define PWR_BASE 0x40007000
/* Flash memory interface */
struct flash_bank {
uint32_t sr; /* +00: Flash status */
uint32_t cr; /* +04: Flash control */
uint32_t ar; /* +08: Flash address */
};
struct flash {
uint32_t psr; /* 00: Performance select */
uint32_t unlock1; /* 04: Bank 1 unlock */
uint32_t opt_unlock;/* 08: Option bytes unlock */
struct flash_bank bank1;
uint32_t rsvd; /* 18: - */
uint32_t obr; /* 1C: Option byte */
uint32_t epps0; /* 20: Erase/program protection */
uint32_t rsvd2[2]; /* 24-28: - */
uint32_t epps1; /* 2C: Erase/program protection */
uint32_t rsvd3[5]; /* 30-40: - */
uint32_t unlock2; /* 44: Bank 2 unlock */
uint32_t rsvd4; /* 48: - */
struct flash_bank bank2;
uint32_t contr; /* 58: Continue read */
uint32_t rsvd5; /* 5C: - */
uint32_t divr; /* 60: Divider */
};
#define FLASH_SR_EOP (1u<< 5)
#define FLASH_SR_WRPRTERR (1u<< 4)
#define FLASH_SR_PGERR (1u<< 2)
#define FLASH_SR_BSY (1u<< 0)
#define FLASH_CR_EOPIE (1u<<12)
#define FLASH_CR_ERRIE (1u<<10)
#define FLASH_CR_OPTWRE (1u<< 9)
#define FLASH_CR_LOCK (1u<< 7)
#define FLASH_CR_ERASE_STRT (1u<< 6)
#define FLASH_CR_OPTER (1u<< 5)
#define FLASH_CR_OPTPG (1u<< 4)
#define FLASH_CR_SEC_ER (1u<< 3)
#define FLASH_CR_BANK_ER (1u<< 2)
#define FLASH_CR_PG_ER (1u<< 1)
#define FLASH_CR_PG (1u<< 0)
#define FLASH_DIVR_DIV_2 (0u<< 0)
#define FLASH_DIVR_DIV_3 (1u<< 0)
#define FLASH_DIVR_DIV_4 (2u<< 0)
#define FLASH_BASE 0x40023c00
/* Reset and clock control */
struct rcc {
uint32_t cr; /* 00: Clock control */
uint32_t pllcfgr; /* 04: PLL configuration */
uint32_t cfgr; /* 08: Clock configuration */
uint32_t cir; /* 0C: Clock interrupt */
uint32_t ahb1rstr; /* 10: AHB1 peripheral reset */
uint32_t ahb2rstr; /* 14: AHB2 peripheral reset */
uint32_t ahb3rstr; /* 18: AHB3 peripheral reset */
uint32_t _unused0; /* 1C: - */
uint32_t apb1rstr; /* 20: APB1 peripheral reset */
uint32_t apb2rstr; /* 24: APB2 peripheral reset */
uint32_t _unused1; /* 28: - */
uint32_t _unused2; /* 2C: - */
uint32_t ahb1enr; /* 30: AHB1 peripheral clock enable */
uint32_t ahb2enr; /* 34: AHB2 peripheral clock enable */
uint32_t ahb3enr; /* 38: AHB3 peripheral clock enable */
uint32_t _unused3; /* 3C: - */
uint32_t apb1enr; /* 40: APB1 peripheral clock enable */
uint32_t apb2enr; /* 44: APB2 peripheral clock enable */
uint32_t _unused4; /* 48: - */
uint32_t _unused5; /* 4C: - */
uint32_t ahb1lpenr;/* 50: AHB1 peripheral clock enable (low-power mode) */
uint32_t ahb2lpenr;/* 54: AHB2 peripheral clock enable (low-power mode) */
uint32_t ahb3lpenr;/* 58: AHB3 peripheral clock enable (low-power mode) */
uint32_t _unused6; /* 5C: - */
uint32_t apb1lpenr;/* 60: APB1 peripheral clock enable (low-power mode) */
uint32_t apb2lpenr;/* 64: APB2 peripheral clock enable (low-power mode) */
uint32_t _unused7; /* 68: - */
uint32_t _unused8; /* 6C: - */
uint32_t bdcr; /* 70: Backup domain control */
uint32_t csr; /* 74: Clock control & status */
uint32_t _unused9[10]; /* 78-9C: - */
uint32_t misc1; /* A0: Misc 1 */
uint32_t misc2; /* A4: Misc 2 */
};
#define RCC_CR_PLLRDY (1u<<25)
#define RCC_CR_PLLON (1u<<24)
#define RCC_CR_CFDEN (1u<<19)
#define RCC_CR_HSEBYP (1u<<18)
#define RCC_CR_HSERDY (1u<<17)
#define RCC_CR_HSEON (1u<<16)
#define RCC_CR_HSIRDY (1u<<1)
#define RCC_CR_HSION (1u<<0)
#define RCC_PLLCFGR_PLLSRC_HSE (1<<22)
#define PLL_FR_2 1
#define RCC_PLLCFGR_PLL_FR(x) ((x)<<16)
#define RCC_PLLCFGR_PLL_NS(x) ((x)<< 6)
#define RCC_PLLCFGR_PLL_MS(x) ((x)<< 0)
#define RCC_CFGR_MCO2(x) ((x)<<30)
#define RCC_CFGR_MCO2PRE(x) ((x)<<27)
#define RCC_CFGR_USBPRE(x) ((x)<<24)
#define RCC_CFGR_MCO1(x) ((x)<<21)
#define RCC_CFGR_RTCPRE(x) ((x)<<16)
#define RCC_CFGR_PPRE2(x) ((x)<<13)
#define RCC_CFGR_PPRE1(x) ((x)<<10)
#define RCC_CFGR_HPRE(x) ((x)<< 4)
#define RCC_CFGR_SWS(x) ((x)<< 2)
#define RCC_CFGR_SW(x) ((x)<< 0)
#define RCC_AHB1ENR_OTGFS2EN (1u<<29)
#define RCC_AHB1ENR_DMA2EN (1u<<24)
#define RCC_AHB1ENR_DMA1EN (1u<<22)
#define RCC_AHB1ENR_EDMAEN (1u<<21)
#define RCC_AHB1ENR_CRCEN (1u<<12)
#define RCC_AHB1ENR_GPIOHEN (1u<< 7)
#define RCC_AHB1ENR_GPIOGEN (1u<< 6)
#define RCC_AHB1ENR_GPIOFEN (1u<< 5)
#define RCC_AHB1ENR_GPIOEEN (1u<< 4)
#define RCC_AHB1ENR_GPIODEN (1u<< 3)
#define RCC_AHB1ENR_GPIOCEN (1u<< 2)
#define RCC_AHB1ENR_GPIOBEN (1u<< 1)
#define RCC_AHB1ENR_GPIOAEN (1u<< 0)
#define RCC_AHB2ENR_OTGFS1EN (1u<< 7)
#define RCC_AHB2ENR_DVPEN (1u<< 0)
#define RCC_AHB3ENR_QSPI2EN (1u<<14)
#define RCC_AHB3ENR_QSPI1EN (1u<< 1)
#define RCC_AHB3ENR_XMCEN (1u<< 0)
#define RCC_APB1ENR_USART8EN (1u<<31)
#define RCC_APB1ENR_USART7EN (1u<<30)
#define RCC_APB1ENR_DACEN (1u<<29)
#define RCC_APB1ENR_PWREN (1u<<28)
#define RCC_APB1ENR_CAN1EN (1u<<25)
#define RCC_APB1ENR_I2C3EN (1u<<23)
#define RCC_APB1ENR_I2C2EN (1u<<22)
#define RCC_APB1ENR_I2C1EN (1u<<21)
#define RCC_APB1ENR_USART5EN (1u<<20)
#define RCC_APB1ENR_USART4EN (1u<<19)
#define RCC_APB1ENR_USART3EN (1u<<18)
#define RCC_APB1ENR_USART2EN (1u<<17)
#define RCC_APB1ENR_SPI3EN (1u<<15)
#define RCC_APB1ENR_SPI2EN (1u<<14)
#define RCC_APB1ENR_WWDGEN (1u<<11)
#define RCC_APB1ENR_TIM14EN (1u<< 8)
#define RCC_APB1ENR_TIM13EN (1u<< 7)
#define RCC_APB1ENR_TIM12EN (1u<< 6)
#define RCC_APB1ENR_TIM7EN (1u<< 5)
#define RCC_APB1ENR_TIM6EN (1u<< 4)
#define RCC_APB1ENR_TIM5EN (1u<< 3)
#define RCC_APB1ENR_TIM4EN (1u<< 2)
#define RCC_APB1ENR_TIM3EN (1u<< 1)
#define RCC_APB1ENR_TIM2EN (1u<< 0)
#define RCC_APB2ENR_ACCEN (1u<<29)
#define RCC_APB2ENR_TIM20EN (1u<<20)
#define RCC_APB2ENR_TIM11EN (1u<<18)
#define RCC_APB2ENR_TIM10EN (1u<<17)
#define RCC_APB2ENR_TIM9EN (1u<<16)
#define RCC_APB2ENR_SYSCFGEN (1u<<14)
#define RCC_APB2ENR_SPI4EN (1u<<13)
#define RCC_APB2ENR_SPI1EN (1u<<12)
#define RCC_APB2ENR_ADC3EN (1u<<10)
#define RCC_APB2ENR_ADC2EN (1u<< 9)
#define RCC_APB2ENR_ADC1EN (1u<< 8)
#define RCC_APB2ENR_USART6EN (1u<< 5)
#define RCC_APB2ENR_USART1EN (1u<< 4)
#define RCC_APB2ENR_TIM8EN (1u<< 1)
#define RCC_APB2ENR_TIM1EN (1u<< 0)
#define RCC_BDCR_BDRST (1u<<16)
#define RCC_BDCR_RTCEN (1u<<15)
#define RCC_BDCR_RTCSEL(x) ((x)<<8)
#define RCC_BDCR_LSEDRV(x) ((x)<<3)
#define RCC_BDCR_LSEBYP (1u<< 2)
#define RCC_BDCR_LSERDY (1u<< 1)
#define RCC_BDCR_LSEON (1u<< 0)
#define RCC_CSR_LPWRRSTF (1u<<31)
#define RCC_CSR_WWDGRSTF (1u<<30)
#define RCC_CSR_IWDGRSTF (1u<<29)
#define RCC_CSR_SFTRSTF (1u<<28)
#define RCC_CSR_PORRSTF (1u<<27)
#define RCC_CSR_PINRSTF (1u<<26)
#define RCC_CSR_BORRSTF (1u<<25)
#define RCC_CSR_RMVF (1u<<24)
#define RCC_CSR_LSIRDY (1u<< 1)
#define RCC_CSR_LSION (1u<< 0)
#define RCC_MISC2_USBDIV(x) ((x)<<12)
#define USBDIV_6 11
#define RCC_MISC2_AUTOSTEP (3u<< 4)
#define RCC_BASE 0x40023800
/* General-purpose I/O */
struct gpio {
uint32_t moder; /* 00: Port mode */
uint32_t otyper; /* 04: Port output type */
uint32_t odrvr; /* 08: Drive capability */
uint32_t pupdr; /* 0C: Port pull-up/pull-down */
uint32_t idr; /* 10: Port input data */
uint32_t odr; /* 14: Port output data */
uint32_t bsrr; /* 18: Port bit set/reset */
uint32_t lckr; /* 1C: Port configuration lock */
uint32_t afrl; /* 20: Alternate function low */
uint32_t afrh; /* 24: Alternate function high */
uint32_t brr; /* 28: Port bit reset */
uint32_t rsvd[4]; /* 2C-38 */
uint32_t hdrv; /* 3C: Huge current control */
};
/* 0-1: MODE, 2: OTYPE, 3-4:ODRV, 5-6:PUPD, 7:OUTPUT_LEVEL */
#define GPI_analog 0x3u
#define GPI(pupd) (0x0u|((pupd)<<5))
#define PUPD_none 0
#define PUPD_up 1
#define PUPD_down 2
#define GPI_floating GPI(PUPD_none)
#define GPI_pull_down GPI(PUPD_down)
#define GPI_pull_up GPI(PUPD_up)
#define GPO_pushpull(speed,level) (0x1u|((speed)<<3)|((level)<<7))
#define GPO_opendrain(speed,level) (0x5u|((speed)<<3)|((level)<<7))
#define AFI(pupd) (0x2u|((pupd)<<5))
#define AFO_pushpull(speed) (0x2u|((speed)<<3))
#define _AFO_pushpull(speed,level) (0x2u|((speed)<<3)|((level)<<7))
#define AFO_opendrain(speed) (0x6u|((speed)<<3))
#define _2MHz 0
#define _10MHz 0
#define _50MHz 0
#define LOW 0
#define HIGH 1
#define GPIOA_BASE 0x40020000
#define GPIOB_BASE 0x40020400
#define GPIOC_BASE 0x40020800
#define GPIOD_BASE 0x40020C00
#define GPIOE_BASE 0x40021000
#define GPIOF_BASE 0x40021400
#define GPIOG_BASE 0x40021800
#define GPIOH_BASE 0x40021C00
/* System configuration controller */
struct syscfg {
uint32_t cfg1; /* 00: Configuration 1 */
uint32_t cfg2; /* 04: Configuration 2 */
uint32_t exticr[4]; /* 08-14: External interrupt configuration #1-4 */
uint32_t _pad[5];
uint32_t uhdrv; /* 2C: Ultra high source/sink strength */
};
#define SYSCFG_BASE 0x40013800
/* EXTI */
#define EXTI_BASE 0x40013c00
/* DMA */
#define DMA1_CH1_IRQ 56
#define DMA1_CH2_IRQ 57
#define DMA1_CH3_IRQ 58
#define DMA1_CH4_IRQ 59
#define DMA1_CH5_IRQ 60
#define DMA1_CH6_IRQ 68
#define DMA1_CH7_IRQ 69
#define DMA1_BASE 0x40026400
#define DMA2_BASE 0x40026600
/* DMAMUX */
struct dmamux {
uint32_t sel; /* 00: Selection */
uint32_t cctrl[7]; /* 04-1C: Channel control */
uint32_t gctrl[4]; /* 20-2C: Generator control */
uint32_t sync_sts; /* 30: Channel synchronisation status */
uint32_t sync_clr; /* 34: Channel synchronisation clear */
uint32_t g_sts; /* 38: Generator interrupt status */
uint32_t g_clr; /* 3C: Generator interrupt clear */
};
#define DMAMUX_SEL_TBL_SEL (1u<< 0)
#define DMAMUX_CCTRL_REQSEL(x) ((x)<<0)
#define DMAMUX_REQ_I2C2_RX 18
#define DMAMUX_REQ_I2C2_TX 19
#define DMAMUX_REQ_TIM1_CH1 42
#define DMAMUX_REQ_TIM3_OVF 65
#define DMAMUX1_BASE (DMA1_BASE + 0x100)
#define DMAMUX2_BASE (DMA2_BASE + 0x100)
/* Timer */
#define TIM_CR1_PMEN (1u<<10)
#define TIM1_BASE 0x40010000
#define TIM2_BASE 0x40000000
#define TIM3_BASE 0x40000400
#define TIM4_BASE 0x40000800
#define TIM5_BASE 0x40000c00
#define TIM6_BASE 0x40001000
#define TIM7_BASE 0x40001400
#define TIM8_BASE 0x40010400
#define TIM9_BASE 0x40014000
#define TIM10_BASE 0x40014400
#define TIM11_BASE 0x40014800
#define TIM12_BASE 0x40001800
#define TIM13_BASE 0x40001c00
#define TIM14_BASE 0x40002000
/* I2C */
struct i2c {
uint32_t cr1; /* 00: Control 1 */
uint32_t cr2; /* 04: Control 2 */
uint32_t oar1; /* 08: Own address 1 */
uint32_t oar2; /* 0C: Own address 2 */
uint32_t timingr; /* 10: Timing */
uint32_t timeoutr;/* 14: Timeout */
uint32_t isr; /* 18: Interrupt status */
uint32_t icr; /* 1C: Interrupt clear */
uint32_t pecr; /* 20: PEC */
uint32_t rxdr; /* 24: Receive data */
uint32_t txdr; /* 28: Transmit data */
};
#define I2C_CR1_PECEN (1u<<23)
#define I2C_CR1_ALERTEN (1u<<22)
#define I2C_CR1_SMBDEN (1u<<21)
#define I2C_CR1_SMBHEN (1u<<20)
#define I2C_CR1_GCEN (1u<<19)
#define I2C_CR1_NOSTRETCH (1u<<17)
#define I2C_CR1_SBC (1u<<16)
#define I2C_CR1_RXDMAEN (1u<<15)
#define I2C_CR1_TXDMAEN (1u<<14)
#define I2C_CR1_ANFOFF (1u<<12)
#define I2C_CR1_DNF(x) ((x)<<8)
#define I2C_CR1_ERRIE (1u<< 7)
#define I2C_CR1_TCIE (1u<< 6)
#define I2C_CR1_STOPIE (1u<< 5)
#define I2C_CR1_NACKIE (1u<< 4)
#define I2C_CR1_ADDRIE (1u<< 3)
#define I2C_CR1_RXIE (1u<< 2)
#define I2C_CR1_TXIE (1u<< 1)
#define I2C_CR1_PE (1u<< 0)
#define I2C_CR2_PECBYTE (1u<<26)
#define I2C_CR2_AUTOEND (1u<<25)
#define I2C_CR2_RELOAD (1u<<24)
#define I2C_CR2_NBYTES(x) ((x)<<16)
#define I2C_CR2_NACK (1u<<15)
#define I2C_CR2_STOP (1u<<14)
#define I2C_CR2_START (1u<<13)
#define I2C_CR2_HEAD10R (1u<<12)
#define I2C_CR2_ADD10 (1u<<11)
#define I2C_CR2_RD_WRN (1u<<10)
#define I2C_CR2_SADD(x) ((x)<<0)
/* Based on 144MHz peripheral clock */
#define I2C_TIMING_100k 0x80504C4E
#define I2C_TIMING_400k 0x40301B28
#define I2C_SR_ERRORS 0x1f10
#define I2C_SR_BUSY (1u<<15)
#define I2C_SR_ALERT (1u<<13)
#define I2C_SR_TIMEOUT (1u<<12)
#define I2C_SR_PECERR (1u<<11)
#define I2C_SR_OVR (1u<<10)
#define I2C_SR_ARLO (1u<< 9)
#define I2C_SR_BERR (1u<< 8)
#define I2C_SR_TCR (1u<< 7)
#define I2C_SR_TC (1u<< 6)
#define I2C_SR_STOPF (1u<< 5)
#define I2C_SR_NACKF (1u<< 4)
#define I2C_SR_ADDR (1u<< 3)
#define I2C_SR_RXNE (1u<< 2)
#define I2C_SR_TXIS (1u<< 1)
#define I2C_SR_TXE (1u<< 0)
#define I2C1_BASE 0x40005400
#define I2C2_BASE 0x40005800
/* USART */
#define USART1_BASE 0x40011000
#define USART2_BASE 0x40004400
#define USART3_BASE 0x40004800
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,71 +0,0 @@
/*
* stm32f105.h
*
* Core and peripheral registers.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* C pointer types */
#define AFIO volatile struct afio * const
/* C-accessible registers. */
static STK stk = (struct stk *)STK_BASE;
static SCB scb = (struct scb *)SCB_BASE;
static NVIC nvic = (struct nvic *)NVIC_BASE;
static DBG dbg = (struct dbg *)DBG_BASE;
static FLASH flash = (struct flash *)FLASH_BASE;
static PWR pwr = (struct pwr *)PWR_BASE;
static BKP bkp = (struct bkp *)BKP_BASE;
static RCC rcc = (struct rcc *)RCC_BASE;
static GPIO gpioa = (struct gpio *)GPIOA_BASE;
static GPIO gpiob = (struct gpio *)GPIOB_BASE;
static GPIO gpioc = (struct gpio *)GPIOC_BASE;
static GPIO gpiod = (struct gpio *)GPIOD_BASE;
static GPIO gpioe = (struct gpio *)GPIOE_BASE;
static GPIO gpiof = (struct gpio *)GPIOF_BASE;
static GPIO gpiog = (struct gpio *)GPIOG_BASE;
static AFIO afio = (struct afio *)AFIO_BASE;
static EXTI exti = (struct exti *)EXTI_BASE;
static DMA dma1 = (struct dma *)DMA1_BASE;
static DMA dma2 = (struct dma *)DMA2_BASE;
static TIM tim1 = (struct tim *)TIM1_BASE;
static TIM tim2 = (struct tim *)TIM2_BASE;
static TIM tim3 = (struct tim *)TIM3_BASE;
static TIM tim4 = (struct tim *)TIM4_BASE;
static TIM tim5 = (struct tim *)TIM5_BASE;
static TIM tim6 = (struct tim *)TIM6_BASE;
static TIM tim7 = (struct tim *)TIM7_BASE;
static SPI spi1 = (struct spi *)SPI1_BASE;
static SPI spi2 = (struct spi *)SPI2_BASE;
static SPI spi3 = (struct spi *)SPI3_BASE;
static I2C i2c1 = (struct i2c *)I2C1_BASE;
static I2C i2c2 = (struct i2c *)I2C2_BASE;
static USART usart1 = (struct usart *)USART1_BASE;
static USART usart2 = (struct usart *)USART2_BASE;
static USART usart3 = (struct usart *)USART3_BASE;
static USB_OTG usb_otg = (struct usb_otg *)USB_OTG_BASE;
/* Clocks */
extern unsigned int sysclk_mhz;
extern unsigned int apb1_mhz;
#define SYSCLK_MHZ sysclk_mhz
#define AHB_MHZ sysclk_mhz
#define APB1_MHZ apb1_mhz
#define APB2_MHZ 72
#define SOFTIRQ_0 43
#define SOFTIRQ_1 44
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,313 +0,0 @@
/*
* stm32f105_regs.h
*
* Core and peripheral register definitions.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* Power control */
struct pwr {
uint32_t cr; /* 00: Power control */
uint32_t csr; /* 04: Power control/status */
};
#define PWR_CR_DBP (1u<< 8)
#define PWR_BASE 0x40007000
/* Flash memory interface */
struct flash {
uint32_t acr; /* 00: Flash access control */
uint32_t keyr; /* 04: FPEC key */
uint32_t optkeyr; /* 08: Flash OPTKEY */
uint32_t sr; /* 0C: Flash status */
uint32_t cr; /* 10: Flash control */
uint32_t ar; /* 14: Flash address */
uint32_t rsvd; /* 18: - */
uint32_t obr; /* 1C: Option byte */
uint32_t wrpr; /* 20: Write protection */
};
#define FLASH_ACR_PRFTBS (1u<< 5)
#define FLASH_ACR_PRFTBE (1u<< 4)
#define FLASH_ACR_HLFCYA (1u<< 3)
#define FLASH_ACR_LATENCY(w) ((w)<<0) /* wait states */
#define FLASH_SR_EOP (1u<< 5)
#define FLASH_SR_WRPRTERR (1u<< 4)
#define FLASH_SR_PGERR (1u<< 2)
#define FLASH_SR_BSY (1u<< 0)
#define FLASH_CR_EOPIE (1u<<12)
#define FLASH_CR_ERRIE (1u<<10)
#define FLASH_CR_OPTWRE (1u<< 9)
#define FLASH_CR_LOCK (1u<< 7)
#define FLASH_CR_STRT (1u<< 6)
#define FLASH_CR_OPTER (1u<< 5)
#define FLASH_CR_OPTPG (1u<< 4)
#define FLASH_CR_MER (1u<< 2)
#define FLASH_CR_PER (1u<< 1)
#define FLASH_CR_PG (1u<< 0)
#define FLASH_BASE 0x40022000
/* Reset and clock control */
struct rcc {
uint32_t cr; /* 00: Clock control */
uint32_t cfgr; /* 04: Clock configuration */
uint32_t cir; /* 08: Clock interrupt */
uint32_t apb2rstr; /* 0C: APB2 peripheral reset */
uint32_t apb1rstr; /* 10: APB1 peripheral reset */
uint32_t ahbenr; /* 14: AHB periphernal clock enable */
uint32_t apb2enr; /* 18: APB2 peripheral clock enable */
uint32_t apb1enr; /* 1C: APB1 peripheral clock enable */
uint32_t bdcr; /* 20: Backup domain control */
uint32_t csr; /* 24: Control/status */
uint32_t ahbstr; /* 28: AHB peripheral clock reset */
uint32_t cfgr2; /* 2C: Clock configuration 2 */
};
#define RCC_CR_PLL3RDY (1u<<29)
#define RCC_CR_PLL3ON (1u<<28)
#define RCC_CR_PLL2RDY (1u<<27)
#define RCC_CR_PLL2ON (1u<<26)
#define RCC_CR_PLLRDY (1u<<25)
#define RCC_CR_PLLON (1u<<24)
#define RCC_CR_CSSON (1u<<19)
#define RCC_CR_HSEBYP (1u<<18)
#define RCC_CR_HSERDY (1u<<17)
#define RCC_CR_HSEON (1u<<16)
#define RCC_CR_HSIRDY (1u<<1)
#define RCC_CR_HSION (1u<<0)
#define RCC_CFGR_PLLMUL(x) (((x)-2)<<18)
#define RCC_CFGR_PLLXTPRE (1u<<17)
#define RCC_CFGR_PLLSRC_HSI (0u<<16)
#define RCC_CFGR_PLLSRC_PREDIV1 (1u<<16)
#define RCC_CFGR_ADCPRE_DIV8 (3u<<14)
#define RCC_CFGR_APB2PSC_2 (4u<<11)
#define RCC_CFGR_APB1PSC_2 (4u<< 8)
#define RCC_CFGR_SWS_HSI (0u<<2)
#define RCC_CFGR_SWS_HSE (1u<<2)
#define RCC_CFGR_SWS_PLL (2u<<2)
#define RCC_CFGR_SWS_MASK (3u<<2)
#define RCC_CFGR_SW_HSI (0u<<0)
#define RCC_CFGR_SW_HSE (1u<<0)
#define RCC_CFGR_SW_PLL (2u<<0)
#define RCC_CFGR_SW_MASK (3u<<0)
#define RCC_AHBENR_ETHMACRXEN (1u<<16)
#define RCC_AHBENR_ETHMACTXEN (1u<<15)
#define RCC_AHBENR_ETHMACEN (1u<<14)
#define RCC_AHBENR_OTGFSEN (1u<<12)
#define RCC_AHBENR_CRCEN (1u<< 6)
#define RCC_AHBENR_FLITFEN (1u<< 4)
#define RCC_AHBENR_SRAMEN (1u<< 2)
#define RCC_AHBENR_DMA2EN (1u<< 1)
#define RCC_AHBENR_DMA1EN (1u<< 0)
#define RCC_APB1ENR_DACEN (1u<<29)
#define RCC_APB1ENR_PWREN (1u<<28)
#define RCC_APB1ENR_BKPEN (1u<<27)
#define RCC_APB1ENR_CAN2EN (1u<<26)
#define RCC_APB1ENR_CAN1EN (1u<<25)
#define RCC_APB1ENR_I2C2EN (1u<<22)
#define RCC_APB1ENR_I2C1EN (1u<<21)
#define RCC_APB1ENR_USART5EN (1u<<20)
#define RCC_APB1ENR_USART4EN (1u<<19)
#define RCC_APB1ENR_USART3EN (1u<<18)
#define RCC_APB1ENR_USART2EN (1u<<17)
#define RCC_APB1ENR_SPI3EN (1u<<15)
#define RCC_APB1ENR_SPI2EN (1u<<14)
#define RCC_APB1ENR_WWDGEN (1u<<11)
#define RCC_APB1ENR_TIM7EN (1u<< 5)
#define RCC_APB1ENR_TIM6EN (1u<< 4)
#define RCC_APB1ENR_TIM5EN (1u<< 3)
#define RCC_APB1ENR_TIM4EN (1u<< 2)
#define RCC_APB1ENR_TIM3EN (1u<< 1)
#define RCC_APB1ENR_TIM2EN (1u<< 0)
#define RCC_APB2ENR_USART1EN (1u<<14)
#define RCC_APB2ENR_SPI1EN (1u<<12)
#define RCC_APB2ENR_TIM1EN (1u<<11)
#define RCC_APB2ENR_ADC2EN (1u<<10)
#define RCC_APB2ENR_ADC1EN (1u<< 9)
#define RCC_APB2ENR_IOPFEN (1u<< 7)
#define RCC_APB2ENR_IOPEEN (1u<< 6)
#define RCC_APB2ENR_IOPDEN (1u<< 5)
#define RCC_APB2ENR_IOPCEN (1u<< 4)
#define RCC_APB2ENR_IOPBEN (1u<< 3)
#define RCC_APB2ENR_IOPAEN (1u<< 2)
#define RCC_APB2ENR_AFIOEN (1u<< 0)
#define RCC_BASE 0x40021000
/* General-purpose I/O */
struct gpio {
uint32_t crl; /* 00: Port configuration low */
uint32_t crh; /* 04: Port configuration high */
uint32_t idr; /* 08: Port input data */
uint32_t odr; /* 0C: Port output data */
uint32_t bsrr; /* 10: Port bit set/reset */
uint32_t brr; /* 14: Port bit reset */
uint32_t lckr; /* 18: Port configuration lock */
};
#define _GPI_pulled(level) (0x8u|((level)<<4))
#define GPI_analog 0x0u
#define GPI_floating 0x4u
#define GPI_pull_down _GPI_pulled(LOW)
#define GPI_pull_up _GPI_pulled(HIGH)
#define GPO_pushpull(speed,level) (0x0u|(speed)|((level)<<4))
#define GPO_opendrain(speed,level) (0x4u|(speed)|((level)<<4))
#define AFO_pushpull(speed) (0x8u|(speed))
#define _AFO_pushpull(speed,level) (0x8u|(speed)|((level)<<4))
#define AFO_opendrain(speed) (0xcu|(speed))
#define _2MHz 2
#define _10MHz 1
#define _50MHz 3
#define LOW 0
#define HIGH 1
#define GPIOA_BASE 0x40010800
#define GPIOB_BASE 0x40010c00
#define GPIOC_BASE 0x40011000
#define GPIOD_BASE 0x40011400
#define GPIOE_BASE 0x40011800
#define GPIOF_BASE 0x40011c00
#define GPIOG_BASE 0x40012000
/* Alternative-function I/O */
struct afio {
uint32_t evcr; /* 00: Event control */
uint32_t mapr; /* 04: AF remap and debug I/O configuration */
uint32_t exticr[4]; /* 08-14: External interrupt configuration #1-4 */
uint32_t rsvd; /* 18: - */
uint32_t mapr2; /* 1C: AF remap and debug I/O configuration #2 */
};
#define AFIO_MAPR_SWJ_CFG_DISABLED (4u<<24)
#define AFIO_MAPR_TIM4_REMAP_FULL (1u<<12)
#define AFIO_MAPR_TIM3_REMAP_FULL (3u<<10)
#define AFIO_MAPR_TIM3_REMAP_PARTIAL (2u<<10)
#define AFIO_MAPR_TIM2_REMAP_FULL (3u<< 8)
#define AFIO_MAPR_TIM2_REMAP_PARTIAL_1 (1u<< 8)
#define AFIO_MAPR_TIM2_REMAP_PARTIAL_2 (2u<< 8)
#define AFIO_MAPR_TIM1_REMAP_FULL (3u<< 6)
#define AFIO_MAPR_TIM1_REMAP_PARTIAL (1u<< 6)
#define AFIO_MAPR_USART3_REMAP_FULL (3u<< 4)
#define AFIO_MAPR_USART3_REMAP_PARTIAL (1u<< 4)
#define AFIO_BASE 0x40010000
/* EXTI */
#define EXTI_BASE 0x40010400
/* DMA */
#define DMA1_CH1_IRQ 11
#define DMA1_CH2_IRQ 12
#define DMA1_CH3_IRQ 13
#define DMA1_CH4_IRQ 14
#define DMA1_CH5_IRQ 15
#define DMA1_CH6_IRQ 16
#define DMA1_CH7_IRQ 17
#define DMA1_BASE 0x40020000
#define DMA2_BASE 0x40020400
/* Timer */
#define TIM1_BASE 0x40012c00
#define TIM2_BASE 0x40000000
#define TIM3_BASE 0x40000400
#define TIM4_BASE 0x40000800
#define TIM5_BASE 0x40000c00
#define TIM6_BASE 0x40001000
#define TIM7_BASE 0x40001400
/* I2C */
struct i2c {
uint32_t cr1; /* 00: Control 1 */
uint32_t cr2; /* 04: Control 2 */
uint32_t oar1; /* 08: Own address 1 */
uint32_t oar2; /* 0C: Own address 2 */
uint32_t dr; /* 10: Data */
uint32_t sr1; /* 14: Status 1 */
uint32_t sr2; /* 18: Status 2 */
uint32_t ccr; /* 1C: Clock control */
uint32_t trise; /* 20: Rise time */
};
#define I2C_CR1_SWRST (1u<<15)
#define I2C_CR1_ALERT (1u<<13)
#define I2C_CR1_PEC (1u<<12)
#define I2C_CR1_POS (1u<<11)
#define I2C_CR1_ACK (1u<<10)
#define I2C_CR1_STOP (1u<< 9)
#define I2C_CR1_START (1u<< 8)
#define I2C_CR1_NOSTRETCH (1u<< 7)
#define I2C_CR1_ENGC (1u<< 6)
#define I2C_CR1_ENPEC (1u<< 5)
#define I2C_CR1_ENARP (1u<< 4)
#define I2C_CR1_SMBTYPE (1u<< 3)
#define I2C_CR1_SMBUS (1u<< 1)
#define I2C_CR1_PE (1u<< 0)
#define I2C_CR2_LAST (1u<<12)
#define I2C_CR2_DMAEN (1u<<11)
#define I2C_CR2_ITBUFEN (1u<<10)
#define I2C_CR2_ITEVTEN (1u<< 9)
#define I2C_CR2_ITERREN (1u<< 8)
#define I2C_CR2_FREQ(x) (x)
#define I2C_SR1_SMBALERT (1u<<15)
#define I2C_SR1_TIMEOUT (1u<<14)
#define I2C_SR1_PECERR (1u<<12)
#define I2C_SR1_OVR (1u<<11)
#define I2C_SR1_AF (1u<<10)
#define I2C_SR1_ARLO (1u<< 9)
#define I2C_SR1_BERR (1u<< 8)
#define I2C_SR1_ERRORS 0xdf00
#define I2C_SR1_TXE (1u<< 7)
#define I2C_SR1_RXNE (1u<< 6)
#define I2C_SR1_STOPF (1u<< 4)
#define I2C_SR1_ADD10 (1u<< 3)
#define I2C_SR1_BTF (1u<< 2)
#define I2C_SR1_ADDR (1u<< 1)
#define I2C_SR1_SB (1u<< 0)
#define I2C_SR1_EVENTS 0x001f
#define I2C_SR2_PEC(x) ((x)<<15)
#define I2C_SR2_DUALF (1u<< 7)
#define I2C_SR2_SMBHOST (1u<< 6)
#define I2C_SR2_SMBDEFAULT (1u<< 5)
#define I2C_SR2_GENCALL (1u<< 4)
#define I2C_SR2_TRA (1u<< 2)
#define I2C_SR2_BUSY (1u<< 1)
#define I2C_SR2_MSL (1u<< 0)
#define I2C_CCR_FS (1u<<15)
#define I2C_CCR_DUTY (1u<<14)
#define I2C_CCR_CCR(x) (x)
#define I2C1_BASE 0x40005400
#define I2C2_BASE 0x40005800
/* USART */
#define USART1_BASE 0x40013800
#define USART2_BASE 0x40004400
#define USART3_BASE 0x40004800
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,5 +1,5 @@
/*
* common.h
* stm32f10x.h
*
* Core and peripheral registers.
*
@ -13,12 +13,12 @@
#define STK volatile struct stk * const
#define SCB volatile struct scb * const
#define NVIC volatile struct nvic * const
#define DBG volatile struct dbg * const
#define FLASH volatile struct flash * const
#define PWR volatile struct pwr * const
#define BKP volatile struct bkp * const
#define RCC volatile struct rcc * const
#define GPIO volatile struct gpio * const
#define AFIO volatile struct afio * const
#define EXTI volatile struct exti * const
#define DMA volatile struct dma * const
#define TIM volatile struct tim * const
@ -27,15 +27,51 @@
#define USART volatile struct usart * const
#define USB_OTG volatile struct usb_otg * const
/* C-accessible registers. */
static STK stk = (struct stk *)STK_BASE;
static SCB scb = (struct scb *)SCB_BASE;
static NVIC nvic = (struct nvic *)NVIC_BASE;
static FLASH flash = (struct flash *)FLASH_BASE;
static PWR pwr = (struct pwr *)PWR_BASE;
static BKP bkp = (struct bkp *)BKP_BASE;
static RCC rcc = (struct rcc *)RCC_BASE;
static GPIO gpioa = (struct gpio *)GPIOA_BASE;
static GPIO gpiob = (struct gpio *)GPIOB_BASE;
static GPIO gpioc = (struct gpio *)GPIOC_BASE;
static GPIO gpiod = (struct gpio *)GPIOD_BASE;
static GPIO gpioe = (struct gpio *)GPIOE_BASE;
static GPIO gpiof = (struct gpio *)GPIOF_BASE;
static GPIO gpiog = (struct gpio *)GPIOG_BASE;
static AFIO afio = (struct afio *)AFIO_BASE;
static EXTI exti = (struct exti *)EXTI_BASE;
static DMA dma1 = (struct dma *)DMA1_BASE;
static DMA dma2 = (struct dma *)DMA2_BASE;
static TIM tim1 = (struct tim *)TIM1_BASE;
static TIM tim2 = (struct tim *)TIM2_BASE;
static TIM tim3 = (struct tim *)TIM3_BASE;
static TIM tim4 = (struct tim *)TIM4_BASE;
static TIM tim5 = (struct tim *)TIM5_BASE;
static TIM tim6 = (struct tim *)TIM6_BASE;
static TIM tim7 = (struct tim *)TIM7_BASE;
static SPI spi1 = (struct spi *)SPI1_BASE;
static SPI spi2 = (struct spi *)SPI2_BASE;
static SPI spi3 = (struct spi *)SPI3_BASE;
static I2C i2c1 = (struct i2c *)I2C1_BASE;
static I2C i2c2 = (struct i2c *)I2C2_BASE;
static USART usart1 = (struct usart *)USART1_BASE;
static USART usart2 = (struct usart *)USART2_BASE;
static USART usart3 = (struct usart *)USART3_BASE;
static USB_OTG usb_otg = (struct usb_otg *)USB_OTG_BASE;
/* NVIC table */
extern uint32_t vector_table[];
/* System */
void stm32_init(void);
void system_reset(void) __attribute__((noreturn));
extern bool_t is_artery_mcu;
void system_reset(void);
/* Clocks */
#define SYSCLK_MHZ 72
#define SYSCLK (SYSCLK_MHZ * 1000000)
#define sysclk_ns(x) (((x) * SYSCLK_MHZ) / 1000)
#define sysclk_us(x) ((x) * SYSCLK_MHZ)
@ -77,7 +113,6 @@ typedef uint32_t stk_time_t;
#define IRQx_get_prio(x) (nvic->ipr[x] >> 4)
/* GPIO */
struct gpio;
void gpio_configure_pin(GPIO gpio, unsigned int pin, unsigned int mode);
#define gpio_write_pin(gpio, pin, level) \
((gpio)->bsrr = ((level) ? 0x1u : 0x10000u) << (pin))
@ -85,23 +120,12 @@ void gpio_configure_pin(GPIO gpio, unsigned int pin, unsigned int mode);
((gpio)->bsrr = (uint32_t)(mask) << ((level) ? 0 : 16))
#define gpio_read_pin(gpio, pin) (((gpio)->idr >> (pin)) & 1)
/* EXTI */
void _exti_route(unsigned int px, unsigned int pin);
#define exti_route_pa(pin) _exti_route(0, pin)
#define exti_route_pb(pin) _exti_route(1, pin)
#define exti_route_pc(pin) _exti_route(2, pin)
/* FPEC */
void fpec_init(void);
void fpec_page_erase(uint32_t flash_address);
void fpec_write(const void *data, unsigned int size, uint32_t flash_address);
#define FLASH_PAGE_SIZE 2048
extern unsigned int flash_page_size;
extern unsigned int ram_kb;
extern uint8_t mcu_package;
enum { MCU_LQFP64=0, MCU_LQFP48, MCU_QFN32 };
/*
* Local variables:

View file

@ -1,5 +1,5 @@
/*
* common_regs.h
* stm32f10x_regs.h
*
* Core and peripheral register definitions.
*
@ -97,17 +97,56 @@ struct nvic {
uint32_t ispr[32]; /* 100: Interrupt set-pending */
uint32_t icpr[32]; /* 180: Interrupt clear-pending */
uint32_t iabr[64]; /* 200: Interrupt active */
uint8_t ipr[100]; /* 300: Interrupt priority */
uint8_t ipr[80]; /* 300: Interrupt priority */
};
#define NVIC_BASE 0xe000e100
struct dbg {
uint32_t mcu_idcode; /* 00: MCU ID code */
uint32_t mcu_cr; /* 04: Debug MCU configuration */
/* Flash memory interface */
struct flash {
uint32_t acr; /* 00: Flash access control */
uint32_t keyr; /* 04: FPEC key */
uint32_t optkeyr; /* 08: Flash OPTKEY */
uint32_t sr; /* 0C: Flash status */
uint32_t cr; /* 10: Flash control */
uint32_t ar; /* 14: Flash address */
uint32_t rsvd; /* 18: - */
uint32_t obr; /* 1C: Option byte */
uint32_t wrpr; /* 20: Write protection */
};
#define DBG_BASE 0xe0042000
#define FLASH_ACR_PRFTBS (1u<< 5)
#define FLASH_ACR_PRFTBE (1u<< 4)
#define FLASH_ACR_HLFCYA (1u<< 3)
#define FLASH_ACR_LATENCY(w) ((w)<<0) /* wait states */
#define FLASH_SR_EOP (1u<< 5)
#define FLASH_SR_WRPRTERR (1u<< 4)
#define FLASH_SR_PGERR (1u<< 2)
#define FLASH_SR_BSY (1u<< 0)
#define FLASH_CR_EOPIE (1u<<12)
#define FLASH_CR_ERRIE (1u<<10)
#define FLASH_CR_OPTWRE (1u<< 9)
#define FLASH_CR_LOCK (1u<< 7)
#define FLASH_CR_STRT (1u<< 6)
#define FLASH_CR_OPTER (1u<< 5)
#define FLASH_CR_OPTPG (1u<< 4)
#define FLASH_CR_MER (1u<< 2)
#define FLASH_CR_PER (1u<< 1)
#define FLASH_CR_PG (1u<< 0)
#define FLASH_BASE 0x40022000
/* Power control */
struct pwr {
uint32_t cr; /* 00: Power control */
uint32_t csr; /* 04: Power control/status */
};
#define PWR_CR_DBP (1u<< 8)
#define PWR_BASE 0x40007000
/* Backup */
struct bkp {
@ -122,7 +161,156 @@ struct bkp {
#define BKP_BASE 0x40006c00
/* EXTI */
/* Reset and clock control */
struct rcc {
uint32_t cr; /* 00: Clock control */
uint32_t cfgr; /* 04: Clock configuration */
uint32_t cir; /* 08: Clock interrupt */
uint32_t apb2rstr; /* 0C: APB2 peripheral reset */
uint32_t apb1rstr; /* 10: APB1 peripheral reset */
uint32_t ahbenr; /* 14: AHB periphernal clock enable */
uint32_t apb2enr; /* 18: APB2 peripheral clock enable */
uint32_t apb1enr; /* 1C: APB1 peripheral clock enable */
uint32_t bdcr; /* 20: Backup domain control */
uint32_t csr; /* 24: Control/status */
uint32_t ahbstr; /* 28: AHB peripheral clock reset */
uint32_t cfgr2; /* 2C: Clock configuration 2 */
};
#define RCC_CR_PLL3RDY (1u<<29)
#define RCC_CR_PLL3ON (1u<<28)
#define RCC_CR_PLL2RDY (1u<<27)
#define RCC_CR_PLL2ON (1u<<26)
#define RCC_CR_PLLRDY (1u<<25)
#define RCC_CR_PLLON (1u<<24)
#define RCC_CR_CSSON (1u<<19)
#define RCC_CR_HSEBYP (1u<<18)
#define RCC_CR_HSERDY (1u<<17)
#define RCC_CR_HSEON (1u<<16)
#define RCC_CR_HSIRDY (1u<<1)
#define RCC_CR_HSION (1u<<0)
#define RCC_CFGR_PLLMUL(x) (((x)-2)<<18)
#define RCC_CFGR_PLLXTPRE (1u<<17)
#define RCC_CFGR_PLLSRC_HSI (0u<<16)
#define RCC_CFGR_PLLSRC_PREDIV1 (1u<<16)
#define RCC_CFGR_ADCPRE_DIV8 (3u<<14)
#define RCC_CFGR_PPRE1_DIV2 (4u<<8)
#define RCC_CFGR_SWS_HSI (0u<<2)
#define RCC_CFGR_SWS_HSE (1u<<2)
#define RCC_CFGR_SWS_PLL (2u<<2)
#define RCC_CFGR_SWS_MASK (3u<<2)
#define RCC_CFGR_SW_HSI (0u<<0)
#define RCC_CFGR_SW_HSE (1u<<0)
#define RCC_CFGR_SW_PLL (2u<<0)
#define RCC_CFGR_SW_MASK (3u<<0)
#define RCC_AHBENR_ETHMACRXEN (1u<<16)
#define RCC_AHBENR_ETHMACTXEN (1u<<15)
#define RCC_AHBENR_ETHMACEN (1u<<14)
#define RCC_AHBENR_OTGFSEN (1u<<12)
#define RCC_AHBENR_CRCEN (1u<< 6)
#define RCC_AHBENR_FLITFEN (1u<< 4)
#define RCC_AHBENR_SRAMEN (1u<< 2)
#define RCC_AHBENR_DMA2EN (1u<< 1)
#define RCC_AHBENR_DMA1EN (1u<< 0)
#define RCC_APB1ENR_DACEN (1u<<29)
#define RCC_APB1ENR_PWREN (1u<<28)
#define RCC_APB1ENR_BKPEN (1u<<27)
#define RCC_APB1ENR_CAN2EN (1u<<26)
#define RCC_APB1ENR_CAN1EN (1u<<25)
#define RCC_APB1ENR_I2C2EN (1u<<22)
#define RCC_APB1ENR_I2C1EN (1u<<21)
#define RCC_APB1ENR_USART5EN (1u<<20)
#define RCC_APB1ENR_USART4EN (1u<<19)
#define RCC_APB1ENR_USART3EN (1u<<18)
#define RCC_APB1ENR_USART2EN (1u<<17)
#define RCC_APB1ENR_SPI3EN (1u<<15)
#define RCC_APB1ENR_SPI2EN (1u<<14)
#define RCC_APB1ENR_WWDGEN (1u<<11)
#define RCC_APB1ENR_TIM7EN (1u<< 5)
#define RCC_APB1ENR_TIM6EN (1u<< 4)
#define RCC_APB1ENR_TIM5EN (1u<< 3)
#define RCC_APB1ENR_TIM4EN (1u<< 2)
#define RCC_APB1ENR_TIM3EN (1u<< 1)
#define RCC_APB1ENR_TIM2EN (1u<< 0)
#define RCC_APB2ENR_USART1EN (1u<<14)
#define RCC_APB2ENR_SPI1EN (1u<<12)
#define RCC_APB2ENR_TIM1EN (1u<<11)
#define RCC_APB2ENR_ADC2EN (1u<<10)
#define RCC_APB2ENR_ADC1EN (1u<< 9)
#define RCC_APB2ENR_IOPEEN (1u<< 6)
#define RCC_APB2ENR_IOPDEN (1u<< 5)
#define RCC_APB2ENR_IOPCEN (1u<< 4)
#define RCC_APB2ENR_IOPBEN (1u<< 3)
#define RCC_APB2ENR_IOPAEN (1u<< 2)
#define RCC_APB2ENR_AFIOEN (1u<< 0)
#define RCC_BASE 0x40021000
/* General-purpose I/O */
struct gpio {
uint32_t crl; /* 00: Port configuration low */
uint32_t crh; /* 04: Port configuration high */
uint32_t idr; /* 08: Port input data */
uint32_t odr; /* 0C: Port output data */
uint32_t bsrr; /* 10: Port bit set/reset */
uint32_t brr; /* 14: Port bit reset */
uint32_t lckr; /* 18: Port configuration lock */
};
#define _GPI_pulled(level) (0x8u|((level)<<4))
#define GPI_analog 0x0u
#define GPI_floating 0x4u
#define GPI_pull_down _GPI_pulled(LOW)
#define GPI_pull_up _GPI_pulled(HIGH)
#define GPO_pushpull(speed,level) (0x0u|(speed)|((level)<<4))
#define GPO_opendrain(speed,level) (0x4u|(speed)|((level)<<4))
#define AFO_pushpull(speed) (0x8u|(speed))
#define AFO_opendrain(speed) (0xcu|(speed))
#define _2MHz 2
#define _10MHz 1
#define _50MHz 3
#define LOW 0
#define HIGH 1
#define GPIOA_BASE 0x40010800
#define GPIOB_BASE 0x40010c00
#define GPIOC_BASE 0x40011000
#define GPIOD_BASE 0x40011400
#define GPIOE_BASE 0x40011800
#define GPIOF_BASE 0x40011c00
#define GPIOG_BASE 0x40012000
/* Alternative-function I/O */
struct afio {
uint32_t evcr; /* 00: Event control */
uint32_t mapr; /* 04: AF remap and debug I/O configuration */
uint32_t exticr1; /* 08: External interrupt configuration #1 */
uint32_t exticr2; /* 0C: External interrupt configuration #2 */
uint32_t exticr3; /* 10: External interrupt configuration #3 */
uint32_t exticr4; /* 14: External interrupt configuration #4 */
uint32_t rsvd; /* 18: - */
uint32_t mapr2; /* 1C: AF remap and debug I/O configuration #2 */
};
#define AFIO_MAPR_SWJ_CFG_DISABLED (4u<<24)
#define AFIO_MAPR_TIM4_REMAP_FULL (1u<<12)
#define AFIO_MAPR_TIM3_REMAP_FULL (3u<<10)
#define AFIO_MAPR_TIM3_REMAP_PARTIAL (2u<<10)
#define AFIO_MAPR_TIM2_REMAP_FULL (3u<< 8)
#define AFIO_MAPR_TIM2_REMAP_PARTIAL_1 (1u<< 8)
#define AFIO_MAPR_TIM2_REMAP_PARTIAL_2 (2u<< 8)
#define AFIO_MAPR_TIM1_REMAP_FULL (3u<< 6)
#define AFIO_MAPR_TIM1_REMAP_PARTIAL (1u<< 6)
#define AFIO_MAPR_USART3_REMAP_FULL (3u<< 4)
#define AFIO_MAPR_USART3_REMAP_PARTIAL (1u<< 4)
#define AFIO_BASE 0x40010000
struct exti {
uint32_t imr; /* 00: Interrupt mask */
uint32_t emr; /* 04: Event mask */
@ -132,6 +320,8 @@ struct exti {
uint32_t pr; /* 14: Pending */
};
#define EXTI_BASE 0x40010400
/* DMA */
struct dma_chn {
uint32_t ccr; /* +00: Configuration */
@ -143,7 +333,13 @@ struct dma_chn {
struct dma {
uint32_t isr; /* 00: Interrupt status */
uint32_t ifcr; /* 04: Interrupt flag clear */
struct dma_chn ch[7];
struct dma_chn ch1; /* 08: Channel 1 */
struct dma_chn ch2; /* 1C: Channel 2 */
struct dma_chn ch3; /* 30: Channel 3 */
struct dma_chn ch4; /* 44: Channel 4 */
struct dma_chn ch5; /* 58: Channel 5 */
struct dma_chn ch6; /* 6C: Channel 6 */
struct dma_chn ch7; /* 80: Channel 7 */
};
/* n=1..7 */
@ -179,6 +375,9 @@ struct dma {
#define DMA_CCR_TCIE (1u<< 1)
#define DMA_CCR_EN (1u<< 0)
#define DMA1_BASE 0x40020000
#define DMA2_BASE 0x40020400
/* Timer */
struct tim {
uint32_t cr1; /* 00: Control 1 */
@ -310,6 +509,14 @@ struct tim {
#define TIM_BDTR_LOCK(x) ((x)<<8)
#define TIM_BDTR_DTG(x) ((x)<<0)
#define TIM1_BASE 0x40012c00
#define TIM2_BASE 0x40000000
#define TIM3_BASE 0x40000400
#define TIM4_BASE 0x40000800
#define TIM5_BASE 0x40000c00
#define TIM6_BASE 0x40001000
#define TIM7_BASE 0x40001400
/* SPI/I2S */
struct spi {
uint32_t cr1; /* 00: Control 1 */
@ -323,17 +530,6 @@ struct spi {
uint32_t i2spr; /* 20: I2S prescaler */
};
#define SPI_BR_DIV2 0
#define SPI_BR_DIV4 1
#define SPI_BR_DIV8 2
#define SPI_BR_DIV16 3
#define SPI_BR_DIV32 4
#define SPI_BR_DIV64 5
#define SPI_BR_DIV128 6
#define SPI_BR_DIV256 7
#define SPI_BR_DIV512 8
#define SPI_BR_DIV1024 9
#define SPI_CR1_BIDIMODE (1u<<15)
#define SPI_CR1_BIDIOE (1u<<14)
#define SPI_CR1_CRCEN (1u<<13)
@ -344,6 +540,15 @@ struct spi {
#define SPI_CR1_SSI (1u<< 8)
#define SPI_CR1_LSBFIRST (1u<< 7)
#define SPI_CR1_SPE (1u<< 6)
#define SPI_CR1_BR_DIV2 (0u<< 3)
#define SPI_CR1_BR_DIV4 (1u<< 3)
#define SPI_CR1_BR_DIV8 (2u<< 3)
#define SPI_CR1_BR_DIV16 (3u<< 3)
#define SPI_CR1_BR_DIV32 (4u<< 3)
#define SPI_CR1_BR_DIV64 (5u<< 3)
#define SPI_CR1_BR_DIV128 (6u<< 3)
#define SPI_CR1_BR_DIV256 (7u<< 3)
#define SPI_CR1_BR_MASK (7u<< 3)
#define SPI_CR1_MSTR (1u<< 2)
#define SPI_CR1_CPOL (1u<< 1)
#define SPI_CR1_CPHA (1u<< 0)
@ -368,6 +573,74 @@ struct spi {
#define SPI2_BASE 0x40003800
#define SPI3_BASE 0x40003C00
/* I2C */
struct i2c {
uint32_t cr1; /* 00: Control 1 */
uint32_t cr2; /* 04: Control 2 */
uint32_t oar1; /* 08: Own address 1 */
uint32_t oar2; /* 0C: Own address 2 */
uint32_t dr; /* 10: Data */
uint32_t sr1; /* 14: Status 1 */
uint32_t sr2; /* 18: Status 2 */
uint32_t ccr; /* 1C: Clock control */
uint32_t trise; /* 20: Rise time */
};
#define I2C_CR1_SWRST (1u<<15)
#define I2C_CR1_ALERT (1u<<13)
#define I2C_CR1_PEC (1u<<12)
#define I2C_CR1_POS (1u<<11)
#define I2C_CR1_ACK (1u<<10)
#define I2C_CR1_STOP (1u<< 9)
#define I2C_CR1_START (1u<< 8)
#define I2C_CR1_NOSTRETCH (1u<< 7)
#define I2C_CR1_ENGC (1u<< 6)
#define I2C_CR1_ENPEC (1u<< 5)
#define I2C_CR1_ENARP (1u<< 4)
#define I2C_CR1_SMBTYPE (1u<< 3)
#define I2C_CR1_SMBUS (1u<< 1)
#define I2C_CR1_PE (1u<< 0)
#define I2C_CR2_LAST (1u<<12)
#define I2C_CR2_DMAEN (1u<<11)
#define I2C_CR2_ITBUFEN (1u<<10)
#define I2C_CR2_ITEVTEN (1u<< 9)
#define I2C_CR2_ITERREN (1u<< 8)
#define I2C_CR2_FREQ(x) (x)
#define I2C_SR1_SMBALERT (1u<<15)
#define I2C_SR1_TIMEOUT (1u<<14)
#define I2C_SR1_PECERR (1u<<12)
#define I2C_SR1_OVR (1u<<11)
#define I2C_SR1_AF (1u<<10)
#define I2C_SR1_ARLO (1u<< 9)
#define I2C_SR1_BERR (1u<< 8)
#define I2C_SR1_ERRORS 0xdf00
#define I2C_SR1_TXE (1u<< 7)
#define I2C_SR1_RXNE (1u<< 6)
#define I2C_SR1_STOPF (1u<< 4)
#define I2C_SR1_ADD10 (1u<< 3)
#define I2C_SR1_BTF (1u<< 2)
#define I2C_SR1_ADDR (1u<< 1)
#define I2C_SR1_SB (1u<< 0)
#define I2C_SR1_EVENTS 0x001f
#define I2C_SR2_PEC(x) ((x)<<15)
#define I2C_SR2_DUALF (1u<< 7)
#define I2C_SR2_SMBHOST (1u<< 6)
#define I2C_SR2_SMBDEFAULT (1u<< 5)
#define I2C_SR2_GENCALL (1u<< 4)
#define I2C_SR2_TRA (1u<< 2)
#define I2C_SR2_BUSY (1u<< 1)
#define I2C_SR2_MSL (1u<< 0)
#define I2C_CCR_FS (1u<<15)
#define I2C_CCR_DUTY (1u<<14)
#define I2C_CCR_CCR(x) (x)
#define I2C1_BASE 0x40005400
#define I2C2_BASE 0x40005800
/* USART */
struct usart {
uint32_t sr; /* 00: Status */
@ -417,6 +690,10 @@ struct usart {
#define USART_CR3_IREN (1u<< 1)
#define USART_CR3_EIE (1u<< 0)
#define USART1_BASE 0x40013800
#define USART2_BASE 0x40004400
#define USART3_BASE 0x40004800
/* USB On-The-Go Full Speed interface */
struct usb_otg {
uint32_t gotctl; /* 00: Control and status */

View file

@ -14,11 +14,9 @@ typedef uint32_t time_t;
#define TIME_MHZ STK_MHZ
#define time_us(x) stk_us(x)
#define time_ms(x) stk_ms(x)
#define time_stk(x) (x)
#define time_sysclk(x) stk_sysclk(x)
#define sysclk_time(x) sysclk_stk(x)
void delay_from(time_t t, unsigned int ticks);
time_t time_now(void);
#define time_diff(x,y) ((int32_t)((y)-(x))) /* d = y - x */

View file

@ -1,56 +0,0 @@
/*
* types.h
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#ifndef NDEBUG
#define ASSERT(p) do { if (!(p)) illegal(); } while (0)
#else
#define ASSERT(p) do { if (0 && (p)) {} } while (0)
#endif
typedef char bool_t;
#define TRUE 1
#define FALSE 0
#ifndef offsetof
#define offsetof(a,b) __builtin_offsetof(a,b)
#endif
#define container_of(ptr, type, member) ({ \
typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define min(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
#define max(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
#define min_t(type,x,y) \
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
#define max_t(type,x,y) \
({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
#define range_t(type,x,a,b) min_t(type, max_t(type, x, a), b)
#define m(bitnr) (1u<<(bitnr))
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -9,6 +9,44 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#ifndef NDEBUG
#define ASSERT(p) do { if (!(p)) illegal(); } while (0)
#else
#define ASSERT(p) do { if (0 && (p)) {} } while (0)
#endif
typedef char bool_t;
#define TRUE 1
#define FALSE 0
#define LONG_MAX ((long int)((~0UL)>>1))
#define LONG_MIN ((long int)~LONG_MAX)
#ifndef offsetof
#define offsetof(a,b) __builtin_offsetof(a,b)
#endif
#define container_of(ptr, type, member) ({ \
typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define min(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
#define max(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
#define min_t(type,x,y) \
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
#define max_t(type,x,y) \
({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
struct slot {
char name[FF_MAX_LFN+1];
char type[7];
@ -19,8 +57,6 @@ struct slot {
};
void fatfs_from_slot(FIL *file, const struct slot *slot, BYTE mode);
bool_t lba_within_fat_volume(uint32_t lba);
void filename_extension(const char *filename, char *extension, size_t size);
/* Fast memset/memcpy: Pointers must be word-aligned, count must be a non-zero
@ -33,9 +69,7 @@ void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char *s);
size_t strnlen(const char *s, size_t maxlen);
int strcmp_ci(const char *s1, const char *s2); /* case insensitive */
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strcpy(char *dest, const char *src);
@ -47,13 +81,6 @@ int isspace(int c);
long int strtol(const char *nptr, char **endptr, int base);
void qsort_p(void *base, unsigned int nr,
int (*compar)(const void *, const void *));
uint32_t rand(void);
unsigned int popcount(uint32_t x);
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
__attribute__ ((format (printf, 3, 0)));
@ -69,8 +96,6 @@ int snprintf(char *str, size_t size, const char *format, ...)
#define htobe16(x) _rev16(x)
#define htobe32(x) _rev32(x)
uint32_t udiv64(uint64_t dividend, uint32_t divisor);
/* Arena-based memory allocation */
void *arena_alloc(uint32_t sz);
uint32_t arena_total(void);
@ -80,35 +105,27 @@ void arena_init(void);
/* Board-specific callouts */
void board_init(void);
#if !defined(NDEBUG) || defined(LOGFILE)
/* Log output, to serial console or logfile. */
int vprintk(const char *format, va_list ap)
__attribute__ ((format (printf, 1, 0)));
int printk(const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
#else /* NDEBUG && !LOGFILE */
static inline int vprintk(const char *format, va_list ap) { return 0; }
static inline int printk(const char *format, ...) { return 0; }
#endif
#ifndef NDEBUG
#define log(f, a...) printk("%s: " f, LOG_PREFIX, ## a)
#if defined(LOGFILE)
/* Logfile management */
void logfile_flush(FIL *file);
#else /* !LOGFILE */
#define logfile_flush(f) ((void)0)
#endif
#if !defined(NDEBUG)
/* Serial console control */
void console_init(void);
void console_sync(void);
void console_crash_on_input(void);
/* Serial console output */
int vprintk(const char *format, va_list ap)
__attribute__ ((format (printf, 1, 0)));
int printk(const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
#else /* NDEBUG */
#define console_init() ((void)0)
#define console_sync() IRQ_global_disable()
#define console_crash_on_input() ((void)0)
static inline int vprintk(const char *format, va_list ap) { return 0; }
static inline int printk(const char *format, ...) { return 0; }
#endif
/* CRC-CCITT */
@ -116,20 +133,17 @@ uint16_t crc16_ccitt(const void *buf, size_t len, uint16_t crc);
/* Display setup and identification. */
void display_init(void);
extern uint8_t display_type;
#define DT_NONE 0
#define DT_LCD_OLED 1
#define DT_LED_7SEG 2
extern uint8_t display_mode;
#define DM_NONE 0
#define DM_LCD_1602 1
#define DM_LED_7SEG 2
/* Speaker. */
void speaker_init(void);
void speaker_pulse(void);
void speaker_notify_insert(unsigned int slotnr);
void speaker_notify_eject(void);
/* Display: 3-digit 7-segment display */
void led_7seg_init(void);
void led_7seg_write_raw(const uint8_t *d);
void led_7seg_write_string(const char *p);
void led_7seg_write_decimal(unsigned int val);
void led_7seg_display_setting(bool_t enable);
@ -143,11 +157,6 @@ void lcd_backlight(bool_t on);
void lcd_sync(void);
extern uint8_t lcd_columns, lcd_rows;
/* FF OSD (On Screen Display) */
extern bool_t has_osd;
extern uint8_t osd_buttons_tx; /* Gotek -> FF_OSD */
extern uint8_t osd_buttons_rx; /* FF_OSD -> Gotek */
/* USB stack processing */
void usbh_msc_init(void);
void usbh_msc_buffer_set(uint8_t *buf);
@ -157,14 +166,9 @@ bool_t usbh_msc_inserted(void);
/* Navigation/UI frontend */
uint16_t get_slot_nr(void);
bool_t set_slot_nr(uint16_t slot_nr);
void set_slot_name(const char *name);
bool_t get_img_cfg(struct slot *slot);
void IRQ_rotary(void);
int set_slot_by_name(const char *name, void *scratch);
enum { DM_normal=0, DM_banner, DM_menu };
extern uint8_t display_mode;
extern uint8_t board_id;
extern uint8_t has_kc30_header;
/* Gotek board revisions */
#define BRDREV_Gotek_standard 0xf
@ -172,24 +176,11 @@ extern uint8_t has_kc30_header;
#define BRDREV_Gotek_sd_card 0x1
#define gotek_enhanced() (board_id != BRDREV_Gotek_standard)
extern uint32_t board_rotary_exti_mask;
void board_setup_rotary_exti(void);
unsigned int board_get_rotary(void);
unsigned int board_get_buttons(void);
#define B_LEFT 1
#define B_RIGHT 2
#define B_SELECT 4
void board_jc_set_mode(unsigned int mode);
bool_t board_jc_strapped(void);
/* Build info. */
extern const char fw_ver[];
extern const char build_date[];
extern const char build_time[];
/* Text/data/BSS address ranges. */
extern char _stext[], _etext[];
extern char _smaintext[], _emaintext[];
extern char _sdat[], _edat[], _ldat[];
extern char _sbss[], _ebss[];
@ -205,13 +196,14 @@ void EXC_unused(void);
#define FLOPPY_IRQ_SEL_PRI 1
#define FLOPPY_IRQ_WGATE_PRI 2
#define FLOPPY_IRQ_STEP_PRI 3
#define FLOPPY_IRQ_SIDE_PRI 4
#define FLOPPY_IRQ_HI_PRI 3
#define TIMER_IRQ_PRI 4
#define WDATA_IRQ_PRI 7
#define RDATA_IRQ_PRI 8
#define FLOPPY_SOFTIRQ_PRI 9
#define I2C_IRQ_PRI 13
#define USB_IRQ_PRI 14
#define CONSOLE_IRQ_PRI 15
/*
* Local variables:

View file

@ -14,8 +14,8 @@
struct volume_ops {
DSTATUS (*initialize)(BYTE);
DSTATUS (*status)(BYTE);
DRESULT (*read)(BYTE, BYTE *, LBA_t, UINT);
DRESULT (*write)(BYTE, const BYTE *, LBA_t, UINT);
DRESULT (*read)(BYTE, BYTE *, DWORD, UINT);
DRESULT (*write)(BYTE, const BYTE *, DWORD, UINT);
DRESULT (*ioctl)(BYTE, BYTE, void *);
bool_t (*connected)(void);
bool_t (*readonly)(void);
@ -24,10 +24,6 @@ struct volume_ops {
bool_t volume_connected(void);
bool_t volume_readonly(void);
void volume_cache_init(void *start, void *end);
void volume_cache_destroy(void);
void volume_cache_metadata_only(FIL *fp);
/*
* Local variables:
* mode: C

28
reloader/Makefile Normal file
View file

@ -0,0 +1,28 @@
RPATH = ../src
OBJS += update.o
OBJS += fpec.o
OBJS += build_info.o
OBJS += cancellation.o
OBJS += crc.o
OBJS += vectors.o
OBJS += fs.o
OBJS += spi.o
OBJS += string.o
OBJS += stm32f10x.o
OBJS += time.o
OBJS += timer.o
OBJS += util.o
OBJS += volume.o
OBJS += flash_cfg.o
OBJS-$(debug) += console.o
SUBDIRS += display
SUBDIRS += fatfs
SUBDIRS += gotek
SUBDIRS += usb
.PHONY: $(RPATH)/build_info.c
build_info.o: CFLAGS += -DFW_VER="\"$(FW_VER)\""

1
reloader/Reloader.ld.S Normal file
View file

@ -0,0 +1 @@
#include "../src/FlashFloppy.ld.S"

View file

@ -0,0 +1,6 @@
RPATH = ../../src/display
OBJS += display.o
OBJS += lcd.o
OBJS += oled_font_6x13.o
OBJS += led_7seg.o

4
reloader/fatfs/Makefile Normal file
View file

@ -0,0 +1,4 @@
RPATH = ../../src/fatfs
OBJS += ff.o
OBJS += ffunicode.o

3
reloader/gotek/Makefile Normal file
View file

@ -0,0 +1,3 @@
RPATH = ../../src/gotek
OBJS += board.o

8
reloader/usb/Makefile Normal file
View file

@ -0,0 +1,8 @@
RPATH = ../../src/usb
OBJS += usb_bsp.o
OBJS += usbh_msc_fatfs.o
SUBDIRS += stm32_usbh_msc
usb%.o: CFLAGS += -I$(ROOT)/src/usb/stm32_usbh_msc/inc/ -include usbh_conf.h

View file

@ -0,0 +1,14 @@
RPATH = ../../../src/usb/stm32_usbh_msc
OBJS += usb_core.o
OBJS += usb_hcd.o
OBJS += usb_hcd_int.o
OBJS += usbh_core.o
OBJS += usbh_hcs.o
OBJS += usbh_ioreq.o
OBJS += usbh_msc_bot.o
OBJS += usbh_msc_core.o
OBJS += usbh_msc_scsi.o
OBJS += usbh_stdreq.o
CFLAGS += -I$(ROOT)/src/usb/stm32_usbh_msc/inc/ -include usbh_conf.h

View file

@ -1,89 +0,0 @@
# check_hex.py
#
# Check the base address and size of segments in an Intel Hex target file,
# based on known constraints for the specified MCU target.
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import os, re, sys
from intelhex import IntelHex
def kb(n):
return n*1024
def _fatal(s):
print('*** ' + s, file=sys.stderr)
def fatal(s):
_fatal(s)
sys.exit(1)
class Target:
FLASH_BASE = 0x8000000
def __init__(self, bootloader_size, flash_size, page_size):
self._bootloader_size = bootloader_size
self._flash_size = flash_size
self._page_size = page_size
def bootloader_base(self):
return self.FLASH_BASE
def bootloader_size(self):
return self._bootloader_size
def firmware_base(self):
return self.FLASH_BASE + self._bootloader_size
def firmware_size(self):
# Allow for bootloader at start of Flash, and cached config at end
return self._flash_size - self._bootloader_size - self._page_size
targets = { 'stm32f105': Target(kb(32), kb(128), kb(2)),
'at32f435': Target(kb(48), kb(256), kb(2)) }
def usage(argv):
fatal("Usage: %s file.hex target" % argv[0])
def main(argv):
if len(argv) != 3:
usage(argv)
h = argv[1]
try:
t = targets[argv[2]]
except KeyError:
_fatal('Unknown target: ' + argv[2])
usage(argv)
# Informational prefix for log lines
prefix = h
m = re.match(r'.*/out/(.*)', os.path.abspath(h))
if m is not None:
prefix = m.group(1)
ih = IntelHex(h)
for (s,e) in ih.segments():
sz = e - s
if s == t.bootloader_base():
if sz > t.bootloader_size():
fatal('%s: Bootloader overflows by %d bytes'
% (prefix, sz - t.bootloader_size()))
print('%s: Bootloader has %d bytes headroom'
% (prefix, t.bootloader_size() - sz))
elif s == t.firmware_base():
if sz > t.firmware_size():
fatal('%s: Firmware overflows by %d bytes'
% (prefix, sz - t.firmware_size()))
print('%s: Firmware has %d bytes headroom'
% (prefix, t.firmware_size() - sz))
else:
fatal('%s: Unexpected start address %x' % (prefix, s))
if __name__ == "__main__":
main(sys.argv)

View file

@ -19,11 +19,11 @@ def main(argv):
tsz = in_dat[52:256]
populated = 0
ext = False
if x[0].startswith(b"EXTENDED CPC DSK File\r\nDisk-Info\r\n"):
if x[0].startswith("EXTENDED CPC DSK File\r\nDisk-Info\r\n"):
print("Extended DSK")
ext = True
else:
assert x[0].startswith(b"MV - CPCEMU")
assert x[0].startswith("MV - CPCEMU")
print("Standard DSK")
while tsz:
x = struct.unpack("B", tsz[:1])

View file

@ -1,56 +0,0 @@
# edsk_double_step.py
#
# Create a double-step EDSK image by doubling up cylinders.
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import struct, sys, random
def main(argv):
if len(argv) != 3:
print("%s <input_file> <output_file>" % argv[0])
return
in_f = open(argv[1], "rb")
in_dat = in_f.read()
out = bytearray(in_dat[:256])
# Check image size
if len(in_dat) < 2048:
print("Not a valid EDSK image - Too short")
return
# Check image header
sig, _, tracks, sides, tsz = struct.unpack("<34s14sBBH", in_dat[:52])
out[48] = tracks * 2 # double up on number of cyls
tszs = in_dat[52:256]
in_dat = in_dat[256:]
if sig.startswith(b"MV - CPCEMU"):
for i in range(tracks):
out += in_dat[:tsz*sides]
for j in range(sides):
out[16-tsz*(j+1)] = i*2 # fix cyl#
out += in_dat[:tsz*sides]
for j in range(sides):
out[16-tsz*(j+1)] = i*2+1 # fix cyl#
in_dat = in_dat[tsz*sides:]
elif sig.startswith(b"EXTENDED CPC DSK File\r\nDisk-Info\r\n"):
for i in range(tracks):
for j in range(2):
off = 0
for k in range(sides):
tsz = tszs[k]*256
out += in_dat[off:off+tsz]
out[16-tsz] = i*2+j # fix cyl#
out[52+(i*2+j)*sides+k] = tszs[k] # fix track size
off += tsz
tszs = tszs[sides:]
in_dat = in_dat[off:]
else:
print("Not a valid EDSK image")
return
with open(argv[2], "wb") as f:
f.write(out)
if __name__ == "__main__":
main(sys.argv)

View file

@ -15,7 +15,7 @@ def main(argv):
out_f.write("/* Autogenerated by " + argv[0] + " */\n")
for line in in_f:
match = re.match("[ \t]*([A-Za-z0-9-]+)[ \t]*=[ \t]*"
"([A-Za-z0-9-,]+|\".*\")", line)
"([A-Za-z0-9-]+|\".*\")", line)
if match:
opt = match.group(1)
val = match.group(2)
@ -25,8 +25,6 @@ def main(argv):
val = "PIN_" + val
elif opt == "track-change":
val = "TRKCHG_" + val
elif opt == "write-drain":
val = "WDRAIN_" + val
elif opt == "host":
val = "HOST_" + val
elif opt == "oled-font":
@ -40,37 +38,11 @@ def main(argv):
h = int(size.group(2))
if w == 128 and h == 64:
opts += ['DISPLAY_oled_64']
elif h >= 2 and h <= 4 and w >= 16 and w <= 40:
elif h == 2 and w >= 16 and w <= 40:
opts += ['DISPLAY_lcd_columns(%d)' % w]
opts += ['DISPLAY_lcd_rows(%d)' % h]
else:
opts += ['DISPLAY_' + x]
val = '|'.join(opts)
elif opt == "notify-volume":
opts = []
for x in val.split(","):
vol = re.match("([0-9]+)", x)
if vol:
opts.append(vol.group(1))
else:
opts.append('NOTIFY_' + x)
val = '|'.join(opts)
elif opt == "display-order" or opt == "osd-display-order":
if val == "default":
val = "DORD_" + val
else:
v = 0
sh = 0
for x in val.split(","):
o = re.match("([0-9])(d?)", x)
v |= int(o.group(1)) << sh
if o.group(2) == "d":
v |= 8 << sh
sh += 4
while sh < 16:
v |= 7 << sh
sh += 4
val = str(v)
elif opt == "image-on-startup":
val = "IMGS_" + val
elif opt == "rotary":
@ -85,22 +57,6 @@ def main(argv):
val = '|'.join(opts)
elif opt == "nav-mode":
val = "NAVMODE_" + val
elif opt == "folder-sort":
val = "SORT_" + val
elif opt == "sort-priority":
val = "SORTPRI_" + val
elif opt == "display-on-activity":
val = "DISPON_" + val
elif opt == "motor-delay":
if val == 'ignore':
val = "MOTOR_" + val
else:
val = (int(val) + 9) // 10
elif opt == "chgrst":
delay = re.match("delay-([0-9]+)", val)
if delay:
val = 'delay(%d)' % int(delay.group(1))
val = "CHGRST_" + val
else:
val = {
'no': 'FALSE',

View file

@ -29,7 +29,7 @@ def main(argv):
gap = 16 - height
tgap = gap // 2
bgap = gap - tgap
out_f.write("const uint8_t %s[] aligned(4) = {\n" % argv[2])
out_f.write("const uint8_t %s[] __aligned(4) = {\n" % argv[2])
for line in in_f:
# Look for a new character encoding
match = re.match("^ENCODING ([0-9]+)", line)

View file

@ -1,65 +0,0 @@
# mk_hfe.py
#
# Make a blank HFE image.
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import sys,struct,argparse
def main(argv):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--rate", type=int, default=250,
help="data rate, kbit/s")
parser.add_argument("--rpm", type=int, default=300,
help="rotational rate, rpm")
parser.add_argument("--cyls", type=int, default=80,
help="number of cylinders")
parser.add_argument("--sides", type=int, default=2,
help="number of sides")
parser.add_argument("outfile", help="output filename")
args = parser.parse_args(argv[1:])
bits = (args.rate * 1000 * 60) // args.rpm
bits *= 2 # clock bits
bits *= 2 # 2 sides
bytes = (bits + 7) // 8 # convert to bytes, rounded up
bytes = (bytes + 15) & ~15 # round up to 16-byte boundary
blocks = (bytes + 511) // 512 # convert to 512-byte blocks, rounded up
print("Geometry: %u cylinders, %u sides" % (args.cyls, args.sides))
print("%ukbit/s @ %uRPM -> %u Encoded Bits"
% (args.rate, args.rpm, bits/2))
print("Data per HFE Track: %u bytes, %u blocks" % (bytes, blocks))
# Header
out_f = open(args.outfile, "wb")
out_f.write(struct.pack("<8s4B2H2BH",
b"HXCPICFE",# signature
0, # revision
args.cyls, # nr_tracks
args.sides, # nr_sides
0xff, # track_encoding
args.rate, # bitrate
0, # rpm
0xfe, # interface_mode
1, # rsvd
1)) # track_list_offset
out_f.write(bytearray(b'\xff'*(512-20)))
# TLUT
tlut_blocks = (args.cyls*4 + 511) // 512
base = 1 + tlut_blocks
for i in range(args.cyls):
out_f.write(struct.pack("<2H", base, bytes))
base += blocks
out_f.write(bytearray(b'\xff'*(tlut_blocks*512-args.cyls*4)))
# Data
out_f.write(bytearray(b'\x88'*(blocks*512*args.cyls)))
if __name__ == "__main__":
main(sys.argv)

View file

@ -1,67 +0,0 @@
# mk_qd.py
#
# Make a blank QD (Quick Disk) image.
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import sys,struct,argparse
def round_up(x, y):
return (x + y - 1) & ~(y - 1)
def main(argv):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--lead-in", type=float, default=0.5,
help="lead-in, seconds")
parser.add_argument("--window", type=float, default=5.5,
help="data window, seconds")
parser.add_argument("--total", type=float, default=8.0,
help="total length, seconds")
parser.add_argument("--round", action="store_true",
help="round values up to 512-byte block size")
parser.add_argument("outfile", help="output filename")
args = parser.parse_args(argv[1:])
lead_in, window, total = args.lead_in, args.window, args.total
assert lead_in >= 0.1, "Insufficient lead-in"
assert total - window - lead_in >= 0.1, "Insufficient lead-out"
bit_ms = 0.004916
total_bytes = int(total * 1000.0 / bit_ms / 8)
window_bytes = int(window * 1000.0 / bit_ms / 8)
init_bytes = int(lead_in * 1000.0 / bit_ms / 8)
if args.round:
total_bytes = round_up(total_bytes, 512)
window_bytes = round_up(window_bytes, 512)
init_bytes = round_up(init_bytes, 512)
print("Lead-In: %.2f sec -> %u bytes" % (lead_in, init_bytes))
print("Window: %.2f sec -> %u bytes" % (window, window_bytes))
print("TOTAL: %.2f sec -> %u bytes" % (total, total_bytes))
# Header
out_f = open(args.outfile, "wb")
out_f.write(struct.pack("<3x2s3x", b"QD"))
out_f.write(bytearray(b'\x00'*(512-8)))
# Track
out_f.write(struct.pack("<4I", 1024, total_bytes, init_bytes,
init_bytes + window_bytes))
out_f.write(bytearray(b'\x00'*(512-16)))
# Data
blocks = (total_bytes + 511) // 512
out_f.write(bytearray(b'\x11'*(blocks*512)))
if __name__ == "__main__":
main(sys.argv)
# Local variables:
# python-indent: 4
# End:

View file

@ -1,156 +1,21 @@
# mk_update.py new <output> <firmware> <model>
# mk_update.py old <output> <firmware>
# mk_update.py verify <update_file>
# mk_update.py
#
# Convert a raw firmware binary into an update file for our bootloader.
#
# New Update Format (Little endian, unless otherwise stated):
# File Header:
# 4 bytes: 'FFUP'
# 4 bytes: <offset to catalogue>
# 4 bytes: <number of catalogue entries>
# Catalogue Entry:
# 1 byte: <hw_model>
# 3 bytes: mbz
# 4 bytes: <offset>
# 4 bytes: <length>
# Catalog Footer:
# 2 bytes: 'FZ'
# 2 bytes: CRC16-CCITT, seed 0xFFFF (big endian)
# Payload Footer:
# 2 bytes: 'FY'
# 2 bytes: CRC16-CCITT, seed 0xFFFF (big endian)
# File Footer:
# 4 bytes: CRC32 (MPEG-2, big endian)
# 4 bytes: 'FFUP'
#
# Old Update Format:
# Convert a raw firmware binary into an update file for our bootloader:
# N bytes: <raw binary data>
# 2 bytes: 'FY'
# 2 bytes: CRC16-CCITT, seed 0xFFFF, stored big endian
#
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import crcmod.predefined
import re, struct, sys, os
import struct, sys
name_to_hw_model = { 'stm32f105': 1,
'at32f435': 4 }
hw_model_to_name = { 1: 'STM32F105',
4: 'AT32F435' }
class Firmware:
def __init__(self,model,binary):
self.model = model
self.binary = binary
def __str__(self):
s = hw_model_to_name[self.model] + ': '
s += '%d bytes' % len(self.binary)
return s
class Catalog:
def __init__(self, f=None):
self.catalog = []
if f is None:
return
b = f.read()
assert len(b) > 12, 'short header'
# Check the file footer
crc32 = crcmod.predefined.Crc('crc-32-mpeg')
crc32.update(b[:-4])
assert crc32.crcValue == 0, 'bad footer crc32'
assert b[-4:] == b'FFUP', 'bad footer signature'
# Check the file header
sig, off, nr = struct.unpack('<4s2I', b[:12])
assert sig == b'FFUP', 'bad header signature'
assert off == 12, 'unexpected header offset'
header_size = off + nr*12 + 4
assert len(b) >= header_size, 'short header'
# Check the header CRC16
crc16 = crcmod.predefined.Crc('crc-ccitt-false')
crc16.update(b[:header_size])
assert crc16.crcValue == 0
for i in range(nr):
# Read catalog entry and payload
m, o, l = struct.unpack('<B3x2I', b[off+i*12:off+(i+1)*12])
assert len(b) >= o+l, 'payload past end of file'
fw = b[o:o+l]
# Check the payload CRC16
crc16 = crcmod.predefined.Crc('crc-ccitt-false')
crc16.update(fw)
assert crc16.crcValue == 0
# Check the payload footer
sig, = struct.unpack('<2s', fw[-4:-2])
assert sig == b'FY', 'Footer signature must be FY'
# All good: Append to the catalog
self.append(Firmware(m, fw))
def append(self,firmware):
# Models must be uniquely represented in the catalog
for fw in self.catalog:
assert fw.model != firmware.model, 'Model already in catalog'
self.catalog.append(firmware)
def serialise(self):
# Header
b = struct.pack('<4s2I', b'FFUP', 12, len(self.catalog))
# Catalog entries
off = 12 + len(self.catalog)*12 + 4
for firmware in self.catalog:
b += struct.pack('<B3x2I', firmware.model, off,
len(firmware.binary))
off += len(firmware.binary)
# Catalog footer
b += b'FZ'
crc16 = crcmod.predefined.Crc('crc-ccitt-false')
crc16.update(b)
b += struct.pack(">H", crc16.crcValue)
# Payloads
for firmware in self.catalog:
b += firmware.binary
# File footer
crc32 = crcmod.predefined.Crc('crc-32-mpeg')
crc32.update(b)
b += struct.pack(">I4s", crc32.crcValue, b'FFUP')
return b
# New: 'flashfloppy-*.upd'
def new_upd(argv):
# Open the catalog, or else create a new one
try:
with open(argv[0], 'rb') as f:
catalog = Catalog(f)
except FileNotFoundError:
catalog = Catalog()
# Read the new firmware payload
with open(argv[1], 'rb') as f:
b = f.read()
assert (len(b) & 3) == 0, "input is not longword padded"
# Append the payload footer
b += b'FY'
crc16 = crcmod.predefined.Crc('crc-ccitt-false')
crc16.update(b)
b += struct.pack(">H", crc16.crcValue)
# Add the new firmware to the catalog
catalog.append(Firmware(name_to_hw_model[argv[2]], b))
# Rewrite the catalog
with open(argv[0], 'wb') as f:
f.write(catalog.serialise())
# Old: 'FF_Gotek*.upd"
def old_upd(argv):
def main(argv):
in_f = open(argv[1], "rb")
out_f = open(argv[0], "wb")
out_f = open(argv[2], "wb")
in_dat = in_f.read()
in_len = len(in_dat)
assert (in_len & 3) == 0, "input is not longword padded"
@ -163,42 +28,5 @@ def old_upd(argv):
in_dat = struct.pack(">H", crc16.crcValue)
out_f.write(in_dat)
def verify_upd(argv):
# Read the file footer to work out type of update file, old vs new
with open(argv[0], 'rb') as f:
f.seek(-4, os.SEEK_END)
sig = f.read(2)
if sig == b'FY':
# Old
print('Old Update File:')
with open(argv[0], 'rb') as f:
b = f.read()
crc16 = crcmod.predefined.Crc('crc-ccitt-false')
crc16.update(b)
assert crc16.crcValue == 0
print(' %s: %d bytes' % (hw_model_to_name[1], len(b)))
else:
# New
print('New Update File:')
with open(argv[0], 'rb') as f:
catalog = Catalog(f)
for firmware in catalog.catalog:
print(' ' + str(firmware))
def main(argv):
if argv[1] == 'new':
dat = new_upd(argv[2:])
elif argv[1] == 'old':
dat = old_upd(argv[2:])
elif argv[1] == 'verify':
verify_upd(argv[2:])
return
else:
assert False
if __name__ == "__main__":
main(sys.argv)
# Local variables:
# python-indent: 4
# End:

View file

@ -1,10 +0,0 @@
# Uncomment the following for clone chips
#set CPUTAPID 0x2ba01477
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/stm32f1x.cfg]
reset_config srst_only connect_assert_srst

View file

@ -1,22 +0,0 @@
# flash.py <hex_filename>
import os, sys, time, telnetlib
cmd = 'reset init ; flash write_image erase %s ; reset\n' % sys.argv[1]
# Start the OpenOCD daemon in the background and connect via telnet
def open_ocd():
os.system('openocd -f scripts/openocd/f1.cfg &')
while True:
time.sleep(0.5)
try:
t = telnetlib.Telnet('localhost', 4444)
except:
pass
else:
return t
with open_ocd() as t:
t.write(cmd.encode('utf-8'))
t.write('shutdown\n'.encode('utf-8'))
t.read_all() # Waits for EOF (telnet session shutdown)

View file

@ -1,29 +0,0 @@
# srcdir.py
#
# Helper script to locate the relative source folder for a given object folder.
# For example:
# objdir = /path/to/out/stm32f105/prod/floppy/usb
# srcdir = ../../../../../src/usb
#
# Written & released by Keir Fraser <keir.xen@gmail.com>
#
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.
import sys, re
# /out/<mcu>/<level>/<target>
NR_LEVELS = 4
objdir = sys.argv[1]
# stem = /out/<mcu>/<level>/target[/<rest_of_path>]
stem = objdir[objdir.rfind('/out'):]
# stem = [/<rest_of_path>]
m = re.match('/[^/]*'*NR_LEVELS+'(/.*)?', stem)
stem = '' if m.group(1) is None else m.group(1)
# srcdir = path to sources, relative to objdir
srcdir = '../'*(NR_LEVELS+stem.count('/')) + 'src' + stem
print(srcdir)

View file

@ -5,42 +5,33 @@ MEMORY
FLASH (rx) : ORIGIN = FLASH_BASE, LENGTH = FLASH_LEN
RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_LEN
}
REGION_ALIAS("RO", FLASH);
REGION_ALIAS("RW", RAM);
SECTIONS
{
.text : {
_stext = .;
*(.vector_table)
*(.vector_table*)
_smaintext = .;
*(.text)
*(.text*)
_emaintext = .;
*(.rodata)
*(.rodata*)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .;
} >FLASH
#if MCU == AT32F435
.flags : {
_reset_flag = .;
. = . + 4;
} >RAM
#endif
} >RO
.data : AT (_etext) {
. = ALIGN(4);
_sdat = .;
*(.data)
*(.data*)
*(.ramfuncs)
. = ALIGN(4);
_edat = .;
_ldat = LOADADDR(.data);
} >RAM
} >RW
.bss : {
. = ALIGN(8);
@ -55,7 +46,7 @@ SECTIONS
*(.bss*)
. = ALIGN(4);
_ebss = .;
} >RAM
} >RW
/DISCARD/ : {
*(.eh_frame)

1
src/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/ff_cfg_defaults.h

7
src/FlashFloppy.ld.S Normal file
View file

@ -0,0 +1,7 @@
#define FLASH_BASE 0x08008000
#define FLASH_LEN 96K
#define RAM_BASE 0x20000000
#define RAM_LEN 64K
#include "../scripts/stm32f10x.ld.S"

View file

@ -5,41 +5,20 @@ OBJS += config.o
OBJS += crc.o
OBJS += flash_cfg.o
OBJS += vectors.o
OBJS += fpec_$(mcu).o
OBJS += floppy.o
OBJS += fpec.o
OBJS += fs.o
OBJS += main.o
OBJS += sd_spi.o
OBJS += spi.o
OBJS += string.o
OBJS += cortex.o mcu_$(mcu).o
OBJS += stm32f10x.o
OBJS += time.o
OBJS += timer.o
OBJS += util.o
OBJS += volume.o
OBJS-$(debug) += console.o
OBJS-$(logfile) += logfile.o
ifeq ($(bl_update),y)
OBJS += bl_update.o
SUBDIRS += display gotek
else ifeq ($(io_test),y)
OBJS += io_test.o
SUBDIRS += display gotek
else ifeq ($(bootloader),y)
OBJS += fw_update.o
SUBDIRS += display fatfs gotek usb
else
OBJS += main.o
OBJS += cache.o
OBJS-$(floppy) += floppy.o
OBJS-$(quickdisk) += quickdisk.o
SUBDIRS += display
SUBDIRS += fatfs
@ -47,17 +26,13 @@ SUBDIRS += image
SUBDIRS += gotek
SUBDIRS += usb
endif
.PHONY: $(SRCDIR)/build_info.c
.PHONY: build_info.c
build_info.o: CFLAGS += -DFW_VER="\"$(FW_VER)\""
# Avoid infinite loops due to GCC noticing code that can be replaced by a call
# to a standard library function... within our implementation of that function.
util.o: CFLAGS += -fno-tree-loop-distribute-patterns
flash_cfg.o: ff_cfg_defaults.h
ff_cfg_defaults.h: $(ROOT)/examples/FF.CFG
$(PYTHON) $(ROOT)/scripts/mk_config.py $< $@
main.o flash_cfg.o: ff_cfg_defaults.h
main.o flash_cfg.o: CFLAGS += -iquote .
clean::
rm -f ff_cfg_defaults.h

View file

@ -9,9 +9,14 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
#define ram_kb 64
#define ram_bytes (ram_kb*1024)
#define heap_bot (_ebss)
#define heap_top ((char *)0x20000000 + ram_bytes)
static char *heap_p;
static char *heap_top;
void *arena_alloc(uint32_t sz)
{
@ -34,7 +39,6 @@ uint32_t arena_avail(void)
void arena_init(void)
{
heap_p = heap_bot;
heap_top = (char *)0x20000000 + ram_kb*1024;
}
/*

View file

@ -1,176 +0,0 @@
/*
* bl_update.c
*
* Main firmware containing a payload of an updated bootloader.
*
* Procedure:
* - Place this *.UPD file on your USB stick and follow usual update process.
*
* Status messages:
* CLr -> Erasing flash
* Prg -> Programming flash
*
* Error messages:
* E05 -> Flash error (bad CRC on verify)
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* Reflash the main bootloader (first 32kB). */
#if MCU == STM32F105
#define FIRMWARE_START 0x08000000
#define FIRMWARE_END 0x08008000
#elif MCU == AT32F435
#define FIRMWARE_START 0x08000000
#define FIRMWARE_END 0x0800c000
#endif
/* The update payload. */
extern char update_start[], update_end[];
asm (
" .section .rodata\n"
" .align 4\n"
" .global update_start, update_end\n"
"update_start:\n"
" .incbin \"../bootloader/target.bin\"\n"
"update_end:\n"
" .previous\n"
);
/* Only the vector table in low 2kB, as we erase first page of firmware,
* and we mustn't erase the code we're executing. */
asm (
" .section .vector_table.padding\n"
" .balign "STR(FLASH_PAGE_SIZE)"\n"
" .previous\n"
);
int EXC_reset(void) __attribute__((alias("main")));
uint8_t board_id;
static void erase_old_firmware(void)
{
uint32_t p;
for (p = FIRMWARE_START; p < FIRMWARE_END; p += flash_page_size)
fpec_page_erase(p);
}
static void msg_display(const char *p)
{
printk("[%s]\n", p);
switch (display_type) {
case DT_LED_7SEG:
led_7seg_write_string(p);
break;
case DT_LCD_OLED:
lcd_write(6, 1, 0, p);
lcd_sync();
break;
}
}
static void display_setting(bool_t on)
{
switch (display_type) {
case DT_LED_7SEG:
led_7seg_display_setting(on);
break;
case DT_LCD_OLED:
lcd_backlight(on);
lcd_sync();
break;
}
}
int main(void)
{
void *buf = update_start;
unsigned int nr = update_end - update_start;
int retries = 0;
/* Relocate DATA. Initialise BSS. */
if (&_sdat[0] != &_ldat[0])
memcpy(_sdat, _ldat, _edat-_sdat);
memset(_sbss, 0, _ebss-_sbss);
/* Initialise the world. */
stm32_init();
time_init();
console_init();
board_init();
delay_ms(200); /* 5v settle */
printk("\n** FF Update Firmware %s for Gotek\n", fw_ver);
printk("** Keir Fraser <keir.xen@gmail.com>\n");
printk("** https://github.com/keirf/FlashFloppy\n\n");
flash_ff_cfg_read();
display_init();
switch (display_type) {
case DT_LED_7SEG:
msg_display("BLD");
break;
case DT_LCD_OLED:
lcd_write(0, 0, 0, "New Bootloader..");
lcd_write(0, 1, 0, " [ ]");
lcd_sync();
break;
}
display_setting(TRUE);
for (retries = 0; retries < 5; retries++) {
/* Erase the old firmware. */
msg_display("CLR");
fpec_init();
erase_old_firmware();
/* Program the new firmware. */
msg_display("PRG");
fpec_write(buf, nr, FIRMWARE_START);
if (!memcmp((void *)FIRMWARE_START, buf, nr))
goto success;
}
/* An error occurred. Report it on the display. */
msg_display("ERR");
/* Erase the bootloader. It's now damaged. */
erase_old_firmware();
/* Spin forever. We're toast. */
for (;;)
continue;
success:
/* No errors. */
printk("Success!\n");
/* Clear the display. */
display_setting(FALSE);
/* All done. Erase ourself and reset. */
IRQ_global_disable();
fpec_page_erase((uint32_t)_stext);
system_reset();
return 0;
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -8,8 +8,6 @@
*/
const char fw_ver[] = FW_VER;
const char build_date[] = __DATE__;
const char build_time[] = __TIME__;
/*
* Local variables:

View file

@ -1,135 +0,0 @@
/*
* cache.c
*
* In-memory data cache.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
struct cache_ent {
uint32_t id;
struct list_head lru;
struct list_head hash;
uint8_t dat[0];
};
struct cache {
uint32_t item_sz;
struct list_head lru;
struct list_head hash[32];
struct cache_ent ents[0];
};
static struct cache *cache;
#define CACHE_HASH(_id) ((_id)&31)
struct cache *cache_init(void *start, void *end, unsigned int item_sz)
{
uint8_t *s, *e;
int i, nitm;
struct cache *c;
struct cache_ent *cent;
/* Cache boundaries are four-byte aligned. */
s = (uint8_t *)(((uint32_t)start + 3) & ~3);
e = (uint8_t *)((uint32_t)end & ~3);
nitm = ((e - s) - (int)sizeof(*c)) / (int)(sizeof(*cent) + item_sz);
if (nitm < 8) {
printk("No cache: too small (%d)\n", e - s);
return NULL;
}
/* Initialise the empty cache structure. */
cache = c = (struct cache *)s;
c->item_sz = item_sz;
list_init(&c->lru);
for (i = 0; i < ARRAY_SIZE(c->hash); i++)
list_init(&c->hash[i]);
/* Insert all the cache entries into the LRU list. They are not present
* in any hash chain as none of the cache entries are yet in use. */
cent = c->ents;
for (i = 0; i < nitm; i++) {
list_insert_tail(&c->lru, &cent->lru);
list_init(&cent->hash);
cent = (struct cache_ent *)((uint32_t)cent + sizeof(*cent) + item_sz);
}
printk("Cache %u items\n", nitm);
return c;
}
const void *cache_lookup(struct cache *c, uint32_t id)
{
struct list_head *hash, *ent;
struct cache_ent *cent;
/* Look up the item in the appropriate hash chain. */
hash = &c->hash[CACHE_HASH(id)];
for (ent = hash->next; ent != hash; ent = ent->next) {
cent = container_of(ent, struct cache_ent, hash);
if (cent->id == id)
goto found;
}
return NULL;
found:
/* Item is cached. Move it to head of LRU and return the data. */
list_remove(&cent->lru);
list_insert_head(&c->lru, &cent->lru);
return cent->dat;
}
void cache_update(struct cache *c, uint32_t id, const void *dat)
{
struct cache_ent *cent;
void *p;
/* Already in the cache? Just update the existing data. */
if ((p = (void *)cache_lookup(c, id)) != NULL)
goto found;
/* Steal the oldest cache entry from the LRU. */
cent = container_of(c->lru.prev, struct cache_ent, lru);
p = cent->dat;
/* Remove the selected cache entry from the cache. */
list_remove(&cent->lru);
if (!list_is_empty(&cent->hash))
list_remove(&cent->hash);
/* Reinsert the cache entry in the correct hash chain, and head of LRU. */
cent->id = id;
list_insert_head(&c->lru, &cent->lru);
list_insert_head(&c->hash[CACHE_HASH(id)], &cent->hash);
found:
/* Finally, store away the actual item data. */
memcpy(p, dat, c->item_sz);
}
void cache_update_N(struct cache *c, uint32_t id,
const void *dat, unsigned int N)
{
const uint8_t *p = dat;
while (N--) {
cache_update(c, id, p);
id++;
p += c->item_sz;
}
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -9,27 +9,23 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
__attribute__((naked))
int call_cancellable_fn(struct cancellation *c, int (*fn)(void *), void *arg) {
asm (
" stmdb.w sp!, {r0, r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
" str sp, [r0]\n" /* c->sp = PSP */
" mov r0, r2\n" /* r0 = arg */
" blx r1\n" /* (*fn)(arg) */
" ldr r2, [sp]\n"
" movs r1, #0\n"
" str r1, [r2]\n" /* c->sp = NULL */
" b do_cancel\n"
);
}
asm (
".global call_cancellable_fn\n"
".thumb_func \n"
"call_cancellable_fn:\n"
" stmdb.w sp!, {r0, r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
" str sp, [r0]\n" /* c->sp = PSP */
" mov r0, r2\n" /* r0 = arg */
" blx r1\n" /* (*fn)(arg) */
" ldr r2, [sp]\n"
" movs r1, #0\n"
" str r1, [r2]\n" /* c->sp = NULL */
"do_cancel:\n"
" add sp, #4\n"
" ldmia.w sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
);
__attribute__((naked))
void do_cancel(void) {
asm (
" add sp, #4\n"
" ldmia.w sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
);
}
void do_cancel(void);
/* An exception context for cancel_call(), when initially called from Thread
* context. */

View file

@ -9,46 +9,34 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* Alphanumeric plus ",-._:" */
static int isvalid(char c)
{
const static char map[] = {
/* , (2c) - (2d) . (2e) 0-9 (30-39) : (3a)
* A-Z (41-5a) _ (5f) a-z (61-7a) */
0x00, 0x00, 0x00, 0x00, /* 0x00-0x1f */
0x00, 0x0e, 0xff, 0xe0, /* 0x20-0x3f */
0x7f, 0xff, 0xff, 0xe1, /* 0x40-0x5f */
0x7f, 0xff, 0xff, 0xe0 /* 0x60-0x7f */
};
return ((c/8) < sizeof(map)) ? (int8_t)(map[c/8] << (c&7)) < 0 : FALSE;
return (((c >= 'A') && (c <= 'Z'))
|| ((c >= 'a') && (c <= 'z'))
|| ((c >= '0') && (c <= '9'))
|| (c == '-') || (c == ','));
}
int get_next_opt(struct opts *opts)
{
char *p, c;
const struct opt *opt;
bool_t section;
F_read(opts->file, &c, 1, NULL);
next_line:
if (c == '\0')
return OPT_eof;
return -1; /* eof */
/* Skip leading whitespace. */
while (isspace(c))
F_read(opts->file, &c, 1, NULL);
/* Option name parsing. */
section = (c == '['); /* "[section]" */
if (section)
F_read(opts->file, &c, 1, NULL);
p = opts->arg;
while (isvalid(c) && ((p-opts->arg) < (opts->argmax-1))) {
*p++ = c;
F_read(opts->file, &c, 1, NULL);
}
*p = '\0';
if (section)
return OPT_section;
/* Look for a match in the accepted options list. */
for (opt = opts->opts; opt->name; opt++)
if (!strcmp(opt->name, opts->arg))
@ -75,7 +63,7 @@ next_line:
F_read(opts->file, &c, 1, NULL);
}
} else {
/* Non-quoted value: restricted character set. */
/* Non-quoted value: pretty much alphanumeric only is accepted. */
while (isvalid(c) && ((p-opts->arg) < (opts->argmax-1))) {
*p++ = c;
F_read(opts->file, &c, 1, NULL);

View file

@ -1,7 +1,7 @@
/*
* console.c
*
* printf-style interface to USART.
* printf-style interface to USART1.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
@ -12,64 +12,12 @@
#define BAUD 3000000 /* 3Mbaud */
#define USART1_IRQ 37
#define USART3_IRQ 39
#if 1
#define usart usart1
#define USART_IRQ USART1_IRQ
#define usart_gpio gpioa
#define usart_tx_pin 9
#define usart_rx_pin 10
#define PCLK (APB2_MHZ * 1000000)
#else
#define usart usart3
#define USART_IRQ USART3_IRQ
#define usart_gpio gpioc
#define usart_tx_pin 10
#define usart_rx_pin 11
#define PCLK (APB1_MHZ * 1000000)
#endif
/* Normally flush to serial is asynchronously executed in a low-pri IRQ. */
#define CONSOLE_SOFTIRQ SOFTIRQ_1
DEFINE_IRQ(CONSOLE_SOFTIRQ, "SOFTIRQ_console");
/* We stage serial output in a ring buffer. */
static char ring[2048];
#define MASK(x) ((x)&(sizeof(ring)-1))
static unsigned int cons, prod;
/* The console can be set into synchronous mode in which case IRQ is disabled
* and the transmit-empty flag is polled manually for each byte. */
static bool_t sync_console;
static void flush_ring_to_serial(void)
static void emit_char(uint8_t c)
{
unsigned int c = cons, p = prod;
barrier();
while (c != p) {
while (!(usart->sr & USART_SR_TXE))
cpu_relax();
usart->dr = ring[MASK(c++)];
}
barrier();
cons = c;
}
static void SOFTIRQ_console(void)
{
flush_ring_to_serial();
}
static void kick_tx(void)
{
if (sync_console) {
flush_ring_to_serial();
} else if (cons != prod) {
IRQx_set_pending(CONSOLE_SOFTIRQ);
}
while (!(usart1->sr & USART_SR_TXE))
cpu_relax();
usart1->dr = c;
}
int vprintk(const char *format, va_list ap)
@ -83,23 +31,20 @@ int vprintk(const char *format, va_list ap)
n = vsnprintf(str, sizeof(str), format, ap);
p = str;
while (((c = *p++) != '\0') && ((prod-cons) != (sizeof(ring) - 1))) {
while ((c = *p++) != '\0') {
switch (c) {
case '\r': /* CR: ignore as we generate our own CR/LF */
break;
case '\n': /* LF: convert to CR/LF (usual terminal behaviour) */
ring[MASK(prod++)] = '\r';
emit_char('\r');
/* fall through */
default:
ring[MASK(prod++)] = c;
emit_char(c);
break;
}
}
kick_tx();
if (!sync_console)
IRQ_global_enable();
IRQ_global_enable();
return n;
}
@ -118,59 +63,33 @@ int printk(const char *format, ...)
void console_sync(void)
{
if (sync_console)
return;
IRQ_global_disable();
sync_console = TRUE;
kick_tx();
/* Leave IRQs globally disabled. */
}
void console_init(void)
{
/* Turn on the clocks. */
#if USART_IRQ == USART1_IRQ
rcc->apb2enr |= RCC_APB2ENR_USART1EN;
#else
rcc->apb1enr |= RCC_APB1ENR_USART3EN;
#endif
/* Enable TX pin for USART output, RX pin as input. */
#if MCU == STM32F105
gpio_configure_pin(usart_gpio, usart_tx_pin, AFO_pushpull(_10MHz));
gpio_configure_pin(usart_gpio, usart_rx_pin, GPI_pull_up);
#elif MCU == AT32F435
gpio_set_af(usart_gpio, usart_tx_pin, 7);
gpio_set_af(usart_gpio, usart_rx_pin, 7);
gpio_configure_pin(usart_gpio, usart_tx_pin, AFO_pushpull(_10MHz));
gpio_configure_pin(usart_gpio, usart_rx_pin, AFI(PUPD_up));
#endif
/* Enable TX pin (PA9) for USART output, RX pin (PA10) as input. */
gpio_configure_pin(gpioa, 9, AFO_pushpull(_10MHz));
gpio_configure_pin(gpioa, 10, GPI_pull_up);
/* BAUD, 8n1. */
usart->brr = PCLK / BAUD;
usart->cr1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
usart->cr3 = 0;
IRQx_set_prio(CONSOLE_SOFTIRQ, CONSOLE_IRQ_PRI);
IRQx_enable(CONSOLE_SOFTIRQ);
usart1->brr = SYSCLK / BAUD;
usart1->cr1 = (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
usart1->cr3 = 0;
}
/* Debug helper: if we get stuck somewhere, calling this beforehand will cause
* any serial input to cause a crash dump of the stuck context. */
void console_crash_on_input(void)
{
if (mcu_package == MCU_QFN32) {
/* Unavailable: PA10 is reassigned from SER_RX to K4 (rotary select
* on the KC30 header). */
return;
}
(void)usart->dr; /* clear UART_SR_RXNE */
usart->cr1 |= USART_CR1_RXNEIE;
IRQx_set_prio(USART_IRQ, RESET_IRQ_PRI);
IRQx_enable(USART_IRQ);
(void)usart1->dr; /* clear UART_SR_RXNE */
usart1->cr1 |= USART_CR1_RXNEIE;
IRQx_set_prio(USART1_IRQ, RESET_IRQ_PRI);
IRQx_enable(USART1_IRQ);
}
/*

1
src/display/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/oled_font_*.c

View file

@ -1,12 +1,13 @@
OBJS += display.o
OBJS += lcd_$(mcu).o
OBJS += lcd.o
OBJS += oled_font_6x13.o
OBJS += led_7seg.o
ifneq ($(bootloader),y)
lcd_$(mcu).o: CFLAGS += -Dfont_extra=1
lcd.o: CFLAGS += -Dfont_extra=1
OBJS += oled_font_8x16.o
endif
oled_font_%.c: $(ROOT)/fonts/%.bdf
$(PYTHON) $(ROOT)/scripts/mk_font.py $< oled_font_$*
clean::
rm -f oled_font_*.c

View file

@ -9,14 +9,14 @@
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
uint8_t display_type;
uint8_t display_mode;
void display_init(void)
{
char name[20];
int probe_ms = ff_cfg.display_probe_ms;
display_type = DT_NONE;
display_mode = DM_NONE;
snprintf(name, sizeof(name), "None");
for (;;) {
@ -24,15 +24,15 @@ void display_init(void)
stk_time_t t = stk_now();
if (lcd_init()) {
display_type = DT_LCD_OLED;
snprintf(name, sizeof(name), "LCD/OLED");
display_mode = DM_LCD_1602;
snprintf(name, sizeof(name), "1602 LCD");
break; /* positive identification */
}
if ((ff_cfg.display_type & 3) == DISPLAY_auto) {
if (ff_cfg.display_type == DISPLAY_auto) {
led_7seg_init();
display_type = DT_LED_7SEG;
snprintf(name, sizeof(name), "%u-Digit LED",
display_mode = DM_LED_7SEG;
snprintf(name, sizeof(name), "%u-Digit 7-Seg LED",
led_7seg_nr_digits());
if (led_7seg_nr_digits() == 3)
break; /* positive identification */

View file

@ -29,22 +29,8 @@
#define CMD_SETDDRADDR 0x80
#define FS_2LINE 0x08
/* FF OSD command set */
#define OSD_BACKLIGHT 0x00 /* [0] = backlight on */
#define OSD_DATA 0x02 /* next columns*rows bytes are text data */
#define OSD_ROWS 0x10 /* [3:0] = #rows */
#define OSD_HEIGHTS 0x20 /* [3:0] = 1 iff row is 2x height */
#define OSD_BUTTONS 0x30 /* [3:0] = button mask */
#define OSD_COLUMNS 0x40 /* [6:0] = #columns */
struct packed i2c_osd_info {
uint8_t protocol_ver;
uint8_t fw_major, fw_minor;
uint8_t buttons;
};
/* STM32 I2C peripheral. */
#define i2c i2c2
#define SCL 10
#define SDA 11
@ -56,59 +42,32 @@ void IRQ_34(void) __attribute__((alias("IRQ_i2c_error")));
#define I2C_EVENT_IRQ 33
void IRQ_33(void) __attribute__((alias("IRQ_i2c_event")));
/* DMA Tx. */
#define DMA_TX_CH 4
#define i2c_tx_dma dma1->ch[DMA_TX_CH-1]
/* DMA Rx. */
#define DMA_RX_CH 5
#define i2c_rx_dma dma1->ch[DMA_RX_CH-1]
bool_t has_osd;
uint8_t osd_buttons_tx;
uint8_t osd_buttons_rx;
#define OSD_no 0
#define OSD_read 1
#define OSD_write 2
static uint8_t in_osd, osd_ver;
#define OSD_I2C_ADDR 0x10
/* DMA completion ISR. */
#define DMA1_CH4_IRQ 14
void IRQ_14(void) __attribute__((alias("IRQ_dma1_ch4_tc")));
static uint8_t _bl;
static uint8_t i2c_addr;
static uint8_t i2c_dead;
static uint8_t i2c_row;
static bool_t is_oled_display;
static uint8_t oled_height;
#define OLED_ADDR 0x3c
enum { OLED_unknown, OLED_ssd1306, OLED_sh1106 };
static uint8_t oled_model;
static void oled_init(void);
static unsigned int oled_prep_buffer(void);
#define I2C_RD TRUE
#define I2C_WR FALSE
static void i2c_start(uint8_t a, unsigned int nr, bool_t rd);
static void i2c_tx_tc(void);
static void i2c_rx_tc(void);
/* Count of display-refresh completions. For synchronisation/flush. */
static volatile uint8_t refresh_count;
/* I2C data buffer. Data is DMAed to the I2C peripheral. */
static uint8_t buffer[256] aligned(4);
static uint8_t buffer[256] __aligned(4);
/* Text buffer, rendered into I2C data and placed into buffer[]. */
static char text[4][40];
static char text[2][40];
/* Columns and rows of text. */
uint8_t lcd_columns, lcd_rows;
/* Current display mode: Affects row ordering and sizing. */
uint8_t display_mode = DM_banner;
#define menu_mode (display_mode == DM_menu)
/* Occasionally the I2C/DMA engine seems to get stuck. Detect this with
* a timeout timer and unwedge it by calling the I2C error handler. */
#define DMA_TIMEOUT time_ms(200)
@ -122,15 +81,16 @@ static void timeout_fn(void *unused)
static void IRQ_i2c_error(void)
{
/* Dump and clear I2C errors. */
printk("I2C: Error (%04x)\n", (uint16_t)(i2c->isr & I2C_SR_ERRORS));
i2c->icr = I2C_SR_ERRORS;
printk("I2C: Error (%04x)\n", (uint16_t)(i2c->sr1 & I2C_SR1_ERRORS));
i2c->sr1 &= ~I2C_SR1_ERRORS;
/* Clear the I2C peripheral. */
i2c->cr1 = 0;
i2c->cr1 = I2C_CR1_PE;
i2c->cr1 = I2C_CR1_SWRST;
/* Clear the DMA controller. */
i2c_tx_dma.ccr = i2c_rx_dma.ccr = 0;
dma1->ch4.ccr = 0;
dma1->ifcr = DMA_IFCR_CGIF(4);
timer_cancel(&timeout_timer);
@ -139,59 +99,34 @@ static void IRQ_i2c_error(void)
static void IRQ_i2c_event(void)
{
uint16_t sr = i2c->isr;
uint16_t sr1 = i2c->sr1;
if (sr & I2C_SR_STOPF) {
i2c->icr = I2C_SR_STOPF;
if (sr & I2C_SR_NACKF) {
/* I2C automatically STOPs on NACK. But it's an error as far
* as we're concerned, so punt it down that path. */
i2c->icr = I2C_SR_NACKF;
IRQx_set_pending(I2C_ERROR_IRQ);
} else if (i2c->cr2 & I2C_CR2_RD_WRN) {
i2c_rx_tc();
} else {
i2c_tx_tc();
}
if (sr1 & I2C_SR1_SB) {
/* Send address. Clears SR1_SB. */
i2c->dr = i2c_addr << 1;
}
if (sr1 & I2C_SR1_ADDR) {
/* Read SR2 clears SR1_ADDR. */
(void)i2c->sr2;
/* No more events: data phase is driven by DMA. */
i2c->cr2 &= ~I2C_CR2_ITEVTEN;
}
}
/* Start an I2C DMA sequence. */
static void dma_start(unsigned int sz)
{
unsigned int addr = in_osd ? OSD_I2C_ADDR : i2c_addr;
ASSERT(sz <= sizeof(buffer));
if (in_osd == OSD_read) {
i2c_rx_dma.ccr = 0;
i2c->cr1 = (I2C_CR1_RXDMAEN | I2C_CR1_ERRIE | I2C_CR1_STOPIE);
i2c_rx_dma.cndtr = sz;
i2c_rx_dma.ccr = (DMA_CCR_MSIZE_8BIT |
DMA_CCR_PSIZE_32BIT |
DMA_CCR_MINC |
DMA_CCR_DIR_P2M |
DMA_CCR_EN);
i2c_start(addr, sz, I2C_RD);
} else {
i2c_tx_dma.ccr = 0;
i2c->cr1 = (I2C_CR1_TXDMAEN | I2C_CR1_ERRIE | I2C_CR1_STOPIE);
i2c_tx_dma.cndtr = sz;
i2c_tx_dma.ccr = (DMA_CCR_MSIZE_8BIT |
DMA_CCR_PSIZE_32BIT |
DMA_CCR_MINC |
DMA_CCR_DIR_M2P |
DMA_CCR_EN);
i2c_start(addr, sz, I2C_WR);
}
dma1->ch4.cmar = (uint32_t)(unsigned long)buffer;
dma1->ch4.cndtr = sz;
dma1->ch4.ccr = (DMA_CCR_MSIZE_8BIT |
DMA_CCR_PSIZE_16BIT |
DMA_CCR_MINC |
DMA_CCR_DIR_M2P |
DMA_CCR_TCIE |
DMA_CCR_EN);
/* Set the timeout timer in case the DMA hangs for any reason. */
timer_set(&timeout_timer, time_now() + DMA_TIMEOUT);
@ -213,125 +148,44 @@ static void emit8(uint8_t **p, uint8_t val, uint8_t signals)
emit4(p, (val << 4) | signals);
}
/* Snapshot text buffer into the command buffer. */
static unsigned int osd_prep_buffer(void)
{
uint16_t order = menu_mode ? 0x7903 : 0x7183;
char *p;
uint8_t *q = buffer;
unsigned int row, rows, heights;
int i;
if (++in_osd == OSD_read) {
memset(buffer, 0x11, sizeof(struct i2c_osd_info));
return sizeof(struct i2c_osd_info);
}
if ((ff_cfg.osd_display_order != DORD_default)
&& (display_mode == DM_normal))
order = ff_cfg.osd_display_order;
heights = rows = 0;
for (i = 3; i >= 0; i--) {
/* Iterate over rows, bottom to top. */
row = order >> (i<<2);
/* Skip all trailing empty rows. */
if ((rows == 0) && ((row&7) == 7))
continue;
/* Count this row and check if it is double height. */
rows++;
heights <<= 1;
if (row & 8)
heights |= 1;
}
*q++ = OSD_BACKLIGHT | !!_bl;
*q++ = OSD_COLUMNS | lcd_columns;
*q++ = OSD_ROWS | rows;
*q++ = OSD_HEIGHTS | heights;
*q++ = OSD_BUTTONS | osd_buttons_tx;
*q++ = OSD_DATA;
for (row = 0; row < rows; row++) {
p = text[(order >> (row * DORD_shift)) & DORD_row];
memcpy(q, p, lcd_columns);
q += lcd_columns;
}
if (i2c_addr == 0)
refresh_count++;
in_osd = OSD_write;
return q - buffer;
}
/* Snapshot text buffer into the command buffer. */
static unsigned int lcd_prep_buffer(void)
{
const static uint8_t row_offs[] = { 0x00, 0x40, 0x14, 0x54 };
uint16_t order;
char *p;
uint8_t *q = buffer;
unsigned int i, row;
unsigned int i, j;
if (i2c_row == lcd_rows) {
i2c_row++;
if (has_osd)
return osd_prep_buffer();
/* We transmit complete display on every DMA. */
refresh_count++;
for (i = 0; i < lcd_rows; i++) {
emit8(&q, CMD_SETDDRADDR | (i*64), 0);
for (j = 0; j < lcd_columns; j++)
emit8(&q, text[i][j], _RS);
}
if (i2c_row > lcd_rows) {
i2c_row = 0;
refresh_count++;
}
order = (lcd_rows == 2) ? 0x7710 : 0x2103;
if ((ff_cfg.display_order != DORD_default) && (display_mode == DM_normal))
order = ff_cfg.display_order;
row = (order >> (i2c_row * DORD_shift)) & DORD_row;
p = (_bl && row < ARRAY_SIZE(text)) ? text[row] : NULL;
emit8(&q, CMD_SETDDRADDR | row_offs[i2c_row], 0);
for (i = 0; i < lcd_columns; i++)
emit8(&q, p ? *p++ : ' ', _RS);
i2c_row++;
return q - buffer;
}
static void i2c_tx_tc(void)
static void IRQ_dma1_ch4_tc(void)
{
unsigned int dma_sz;
/* Clear the DMA controller. */
dma1->ch4.ccr = 0;
dma1->ifcr = DMA_IFCR_CGIF(4);
/* Prepare the DMA buffer and start the next DMA sequence. */
in_osd = OSD_no;
if (i2c_addr == 0) {
dma_sz = osd_prep_buffer();
} else {
dma_sz = is_oled_display ? oled_prep_buffer() : lcd_prep_buffer();
}
dma_sz = is_oled_display ? oled_prep_buffer() : lcd_prep_buffer();
dma_start(dma_sz);
}
static void i2c_rx_tc(void)
{
struct i2c_osd_info *info = (struct i2c_osd_info *)buffer;
osd_buttons_rx = info->buttons;
/* Now do the OSD write. */
dma_start(osd_prep_buffer());
}
/* Wait for given status condition @s while also checking for errors. */
static bool_t i2c_wait(uint8_t s)
{
stk_time_t t = stk_now();
while ((i2c->isr & s) != s) {
if (i2c->isr & I2C_SR_ERRORS) {
i2c->icr = I2C_SR_ERRORS;
while ((i2c->sr1 & s) != s) {
if (i2c->sr1 & I2C_SR1_ERRORS) {
i2c->sr1 &= ~I2C_SR1_ERRORS;
return FALSE;
}
if (stk_diff(t, stk_now()) > stk_ms(10)) {
@ -343,90 +197,43 @@ static bool_t i2c_wait(uint8_t s)
return TRUE;
}
static void i2c_start(uint8_t a, unsigned int nr, bool_t rd)
/* Synchronously transmit the I2C START sequence. */
static bool_t i2c_start(uint8_t a)
{
uint32_t cr2 = 0;
ASSERT(nr <= 255);
i2c->cr1 &= ~I2C_CR1_PE;
i2c->cr1 |= I2C_CR1_PE;
if (rd)
cr2 |= I2C_CR2_RD_WRN;
cr2 |= I2C_CR2_NBYTES(nr) | I2C_CR2_SADD(a<<1) | I2C_CR2_AUTOEND;
i2c->cr2 = cr2;
i2c->cr2 |= I2C_CR2_START;
}
/* Synchronously transmit the I2C STOP sequence. */
static bool_t i2c_stop(void)
{
if (!i2c_wait(I2C_SR_STOPF))
i2c->cr1 |= I2C_CR1_START;
if (!i2c_wait(I2C_SR1_SB))
return FALSE;
i2c->icr = I2C_SR_STOPF;
i2c->dr = a << 1;
if (!i2c_wait(I2C_SR1_ADDR))
return FALSE;
(void)i2c->sr2;
return TRUE;
}
/* Synchronously transmit an I2C byte. */
static bool_t i2c_sync_write(uint8_t b)
/* Synchronously transmit an I2C command. */
static bool_t i2c_cmd(uint8_t cmd)
{
if (!i2c_wait(I2C_SR_TXIS))
return FALSE;
i2c->txdr = b;
return TRUE;
}
/* Synchronously transmitreceive an I2C byte. */
static bool_t i2c_sync_read(uint8_t *pb)
{
if (!i2c_wait(I2C_SR_RXNE))
return FALSE;
*pb = i2c->rxdr;
return TRUE;
}
static bool_t i2c_sync_write_txn(uint8_t addr, uint8_t *cmds, unsigned int nr)
{
unsigned int i;
i2c_start(addr, nr, I2C_WR);
for (i = 0; i < nr; i++)
if (!i2c_sync_write(*cmds++))
return FALSE;
return i2c_stop();
}
static bool_t i2c_sync_read_txn(uint8_t addr, uint8_t *rsp, unsigned int nr)
{
unsigned int i;
i2c_start(addr, nr, I2C_RD);
for (i = 0; i < nr; i++)
if (!i2c_sync_read(rsp+i))
return FALSE;
return i2c_stop();
i2c->dr = cmd;
return i2c_wait(I2C_SR1_BTF);
}
/* Write a 4-bit nibble over D7-D4 (4-bit bus). */
static void write4(uint8_t val)
{
i2c_sync_write(val);
i2c_sync_write(val | _EN);
i2c_sync_write(val);
i2c_cmd(val);
i2c_cmd(val | _EN);
i2c_cmd(val);
}
/* Check whether an I2C device is responding at given address. */
static bool_t i2c_probe(uint8_t a)
{
i2c_start(a, 1, I2C_WR);
if (!i2c_sync_write(0))
if (!i2c_start(a) || !i2c_cmd(0))
return FALSE;
return i2c_stop();
i2c->cr1 |= I2C_CR1_STOP;
while (i2c->cr1 & I2C_CR1_STOP)
continue;
return TRUE;
}
/* Check given inclusive range of addresses for a responding I2C device. */
@ -441,7 +248,8 @@ static uint8_t i2c_probe_range(uint8_t s, uint8_t e)
void lcd_clear(void)
{
memset(text, ' ', sizeof(text));
lcd_write(0, 0, -1, "");
lcd_write(0, 1, -1, "");
}
void lcd_write(int col, int row, int min, const char *str)
@ -449,6 +257,10 @@ void lcd_write(int col, int row, int min, const char *str)
char c, *p;
uint32_t oldpri;
if (row < 0)
row += lcd_rows;
if (col < 0)
col += lcd_columns;
if (min < 0)
min = lcd_columns;
@ -483,12 +295,7 @@ void lcd_sync(void)
bool_t lcd_init(void)
{
uint8_t a, *p;
bool_t reinit = (i2c_addr != 0) || has_osd;
i2c_dead = FALSE;
i2c_row = 0;
in_osd = OSD_no;
osd_buttons_rx = 0;
bool_t reinit = (i2c_addr != 0);
rcc->apb1enr |= RCC_APB1ENR_I2C2EN;
@ -520,82 +327,56 @@ bool_t lcd_init(void)
/* Check the bus is not floating (or still stuck!). We shouldn't be able to
* pull the lines low with our internal weak pull-downs (min. 30kohm). */
if (!reinit) {
bool_t scl, sda;
gpio_configure_pin(gpiob, SCL, GPI_pull_down);
gpio_configure_pin(gpiob, SDA, GPI_pull_down);
delay_us(10);
scl = gpio_read_pin(gpiob, SCL);
sda = gpio_read_pin(gpiob, SDA);
if (!scl || !sda) {
printk("I2C: Invalid bus SCL=%u SDA=%u\n", scl, sda);
if (!gpio_read_pin(gpiob, SCL) || !gpio_read_pin(gpiob, SDA)) {
printk("I2C: Invalid bus\n");
goto fail;
}
}
gpio_set_af(gpiob, SCL, 4);
gpio_set_af(gpiob, SDA, 4);
gpio_configure_pin(gpiob, SCL, AFO_opendrain(_2MHz));
gpio_configure_pin(gpiob, SDA, AFO_opendrain(_2MHz));
/* Standard Mode (100kHz) */
i2c->timingr = I2C_TIMING_100k;
i2c->cr1 = 0;
i2c->cr2 = I2C_CR2_FREQ(36);
i2c->ccr = I2C_CCR_CCR(180);
i2c->trise = 37;
i2c->cr1 = I2C_CR1_PE;
if (!reinit) {
/* First probe after I2C re-initialisation seems to fail, and so we
* fail to detect FF OSD. So issue a dummy probe first. */
(void)i2c_probe(0);
/* Probe the bus for I2C devices: We support a single LCD/OLED plus
* an FF OSD device. */
has_osd = i2c_probe(OSD_I2C_ADDR);
/* Probe the bus for an I2C device. */
a = i2c_probe_range(0x20, 0x27) ?: i2c_probe_range(0x38, 0x3f);
if ((a == 0) && (i2c_dead || !has_osd
|| ((ff_cfg.display_type & 3) != DISPLAY_auto))) {
if (a == 0) {
printk("I2C: %s\n",
i2c_dead ? "Bus locked up?" : "No device found");
has_osd = FALSE;
goto fail;
}
/* Probe the FF OSD device if we found one. */
if (has_osd) {
(void)i2c_sync_read_txn(OSD_I2C_ADDR, &osd_ver, 1);
printk("I2C: FF OSD found (ver %x)\n", osd_ver);
}
is_oled_display = (ff_cfg.display_type & DISPLAY_oled) ? TRUE
: (ff_cfg.display_type & DISPLAY_lcd) ? FALSE
: ((a&~1) == OLED_ADDR);
lcd_rows = 2;
if (is_oled_display) {
oled_height = (ff_cfg.display_type & DISPLAY_oled_64) ? 64 : 32;
lcd_columns = (ff_cfg.oled_font == FONT_8x16) ? 16
: (ff_cfg.display_type & DISPLAY_narrower) ? 16
: (ff_cfg.display_type & DISPLAY_narrow) ? 18 : 21;
lcd_rows = 4;
} else {
lcd_columns = (ff_cfg.display_type >> _DISPLAY_lcd_columns) & 63;
lcd_rows = (ff_cfg.display_type >> _DISPLAY_lcd_rows) & 7;
lcd_columns = max_t(uint8_t, lcd_columns, 16);
lcd_columns = min_t(uint8_t, lcd_columns, 40);
}
if (a != 0) {
printk("I2C: %s found at 0x%02x\n",
is_oled_display ? "OLED" : "LCD", a);
i2c_addr = a;
} else {
is_oled_display = FALSE;
lcd_columns = ff_cfg.osd_columns;
}
lcd_columns = max_t(uint8_t, lcd_columns, 16);
lcd_columns = min_t(uint8_t, lcd_columns, 40);
lcd_rows = max_t(uint8_t, lcd_rows, 2);
lcd_rows = min_t(uint8_t, lcd_rows, 4);
printk("I2C: %s found at 0x%02x\n",
is_oled_display ? "OLED" : "LCD", a);
i2c_addr = a;
lcd_clear();
}
/* Enable the Event IRQ. */
@ -607,17 +388,14 @@ bool_t lcd_init(void)
IRQx_set_prio(I2C_ERROR_IRQ, I2C_IRQ_PRI);
IRQx_clear_pending(I2C_ERROR_IRQ);
IRQx_enable(I2C_ERROR_IRQ);
dmamux1->cctrl[DMA_TX_CH-1] = DMAMUX_CCTRL_REQSEL(DMAMUX_REQ_I2C2_TX);
dmamux1->cctrl[DMA_RX_CH-1] = DMAMUX_CCTRL_REQSEL(DMAMUX_REQ_I2C2_RX);
i2c->cr2 |= I2C_CR2_ITERREN;
/* Initialise DMA1 channel 4 and its completion interrupt. */
i2c_tx_dma.cmar = (uint32_t)(unsigned long)buffer;
i2c_tx_dma.cpar = (uint32_t)(unsigned long)&i2c->txdr;
/* Initialise DMA1 channel 5 and its completion interrupt. */
i2c_rx_dma.cmar = (uint32_t)(unsigned long)buffer;
i2c_rx_dma.cpar = (uint32_t)(unsigned long)&i2c->rxdr;
dma1->ch4.cpar = (uint32_t)(unsigned long)&i2c->dr;
dma1->ifcr = DMA_IFCR_CGIF(4);
IRQx_set_prio(DMA1_CH4_IRQ, I2C_IRQ_PRI);
IRQx_clear_pending(DMA1_CH4_IRQ);
IRQx_enable(DMA1_CH4_IRQ);
/* Timeout handler for if I2C transmission borks. */
timer_init(&timeout_timer, timeout_fn, NULL);
@ -626,21 +404,19 @@ bool_t lcd_init(void)
if (is_oled_display) {
oled_init();
return TRUE;
} else if (i2c_addr == 0) {
dma_start(osd_prep_buffer());
return TRUE;
}
if (!i2c_start(i2c_addr))
goto fail;
/* Initialise 4-bit interface, as in the datasheet. Do this synchronously
* and with the required delays. */
i2c_start(i2c_addr, 4*3, I2C_WR);
write4(3 << 4);
delay_us(4100);
write4(3 << 4);
delay_us(100);
write4(3 << 4);
write4(2 << 4);
i2c_stop();
/* More initialisation from the datasheet. Send by DMA. */
p = buffer;
@ -648,19 +424,23 @@ bool_t lcd_init(void)
emit8(&p, CMD_DISPLAYCTL, 0);
emit8(&p, CMD_ENTRYMODE | 2, 0);
emit8(&p, CMD_DISPLAYCTL | 4, 0); /* display on */
i2c->cr2 |= I2C_CR2_DMAEN;
dma_start(p - buffer);
if (!reinit)
/* Wait for DMA engine to initialise RAM, then turn on backlight. */
if (!reinit) {
lcd_sync();
lcd_backlight(TRUE);
}
return TRUE;
fail:
if (reinit)
return FALSE;
IRQx_disable(I2C_EVENT_IRQ);
IRQx_disable(I2C_ERROR_IRQ);
i2c->cr1 = 0;
IRQx_disable(DMA1_CH4_IRQ);
i2c->cr1 &= ~I2C_CR1_PE;
gpio_configure_pin(gpiob, SCL, GPI_pull_up);
gpio_configure_pin(gpiob, SDA, GPI_pull_up);
rcc->apb1enr &= ~RCC_APB1ENR_I2C2EN;
@ -722,6 +502,8 @@ static void oled_convert_text_row(char *pc)
oled_convert_text_row_6x13(pc);
}
static uint8_t oled_row;
static unsigned int oled_queue_cmds(
uint8_t *buf, const uint8_t *cmds, unsigned int nr)
{
@ -779,10 +561,7 @@ static unsigned int oled_start_i2c(uint8_t *buf)
static const uint8_t ssd1306_addr_cmds[] = {
0x20, 0, /* horizontal addressing mode */
0x21, 0, 127, /* column address range: 0-127 */
0x22, /* page address range: ?-? */
}, ztech_addr_cmds[] = {
0xda, 0x12, /* alternate com pins config */
0x21, 4, 131, /* column address range: 4-131 */
0x22, 0, /*?*//* page address range: 0-? */
}, sh1106_addr_cmds[] = {
0x10 /* column address high nibble is zero */
};
@ -791,17 +570,16 @@ static unsigned int oled_start_i2c(uint8_t *buf)
uint8_t *p = buf;
/* Set up the display address range. */
if (oled_model == OLED_sh1106) {
if (ff_cfg.display_type & DISPLAY_sh1106) {
p += oled_queue_cmds(p, sh1106_addr_cmds, sizeof(sh1106_addr_cmds));
/* Column address: 0 or 2 (seems 128x64 displays are shifted by 2). */
*dc++ = (oled_height == 64) ? 0x02 : 0x00;
/* Page address: according to i2c_row. */
*dc++ = 0xb0 + i2c_row;
/* Page address: according to oled_row. */
*dc++ = 0xb0 + oled_row;
} else {
p += oled_queue_cmds(p, ssd1306_addr_cmds, sizeof(ssd1306_addr_cmds));
/* Page address: according to i2c_row. */
*dc++ = i2c_row;
*dc++ = 7;
/* Page address max: depends on display height */
*dc++ = (oled_height / 8) - 1;
}
/* Display on/off according to backlight setting. */
@ -809,130 +587,98 @@ static unsigned int oled_start_i2c(uint8_t *buf)
p += oled_queue_cmds(p, dynamic_cmds, dc - dynamic_cmds);
/* ZHONGJY_TECH 2.23" 128x32 display based on SSD1305 controller.
* It has alternate COM pin mapping and is offset horizontally. */
if (ff_cfg.display_type & DISPLAY_ztech)
p += oled_queue_cmds(p, ztech_addr_cmds, sizeof(ztech_addr_cmds));
/* All subsequent bytes are data bytes. */
*p++ = 0x40;
/* Start the I2C transaction. */
i2c->cr2 |= I2C_CR2_ITEVTEN;
i2c->cr1 |= I2C_CR1_START;
return p - buf;
}
static int oled_to_lcd_row(int in_row)
static unsigned int ssd1306_prep_buffer(void)
{
uint16_t order;
int i = 0, row;
bool_t large = FALSE;
order = (oled_height == 32) ? 0x7710 : menu_mode ? 0x7903 : 0x7183;
if ((ff_cfg.display_order != DORD_default) && (display_mode == DM_normal))
order = ff_cfg.display_order;
for (;;) {
large = !!(order & DORD_double);
i += large ? 2 : 1;
if (i > in_row)
break;
order >>= DORD_shift;
}
/* Remap the row */
row = order & DORD_row;
if (row < lcd_rows) {
oled_convert_text_row(text[row]);
} else {
memset(buffer, 0, 256);
}
return large ? i - in_row : 0;
}
/* Snapshot text buffer into the bitmap buffer. */
static unsigned int oled_prep_buffer(void)
{
int size;
uint8_t *p = buffer;
if (i2c_row == (oled_height / 8)) {
i2c_row++;
if (has_osd)
return osd_prep_buffer();
}
if (i2c_row > (oled_height / 8)) {
i2c_row = 0;
/* If we have completed a complete fill of the OLED display, start a new
* I2C transaction. The OLED display seems to occasionally silently lose
* a byte and then we lose sync with the display address. */
if (oled_row == (oled_height / 16)) {
/* Wait for BTF. */
while (!(i2c->sr1 & I2C_SR1_BTF)) {
/* Any errors: bail and leave it to the Error ISR. */
if (i2c->sr1 & I2C_SR1_ERRORS)
return 0;
}
/* Send STOP. Clears SR1_TXE and SR1_BTF. */
i2c->cr1 |= I2C_CR1_STOP;
while (i2c->cr1 & I2C_CR1_STOP)
continue;
/* Kick off new I2C transaction. */
oled_row = 0;
refresh_count++;
return oled_start_i2c(buffer);
}
/* Convert one row of text[] into buffer[] writes. */
size = oled_to_lcd_row(i2c_row/2);
if (size != 0) {
oled_double_height(&buffer[128], &buffer[(size == 1) ? 128 : 0],
(i2c_row & 1) + 1);
if (oled_height == 64) {
oled_convert_text_row(text[oled_row/2]);
oled_double_height(buffer, &buffer[(oled_row & 1) ? 128 : 0], 0x3);
} else {
if (!(i2c_row & 1))
oled_convert_text_row(text[oled_row]);
}
oled_row++;
return 256;
}
static unsigned int sh1106_prep_buffer(void)
{
uint8_t *p = buffer;
/* Convert one row of text[] into buffer[] writes. */
if (oled_height == 64) {
oled_convert_text_row(text[oled_row/4]);
oled_double_height(&buffer[128], &buffer[(oled_row & 2) ? 128 : 0],
(oled_row & 1) + 1);
} else {
oled_convert_text_row(text[oled_row/2]);
if (!(oled_row & 1))
memcpy(&buffer[128], &buffer[0], 128);
}
/* New I2C transaction. */
/* Wait for BTF. */
while (!(i2c->sr1 & I2C_SR1_BTF)) {
/* Any errors: bail and leave it to the Error ISR. */
if (i2c->sr1 & I2C_SR1_ERRORS)
return 0;
}
/* Send STOP. Clears SR1_TXE and SR1_BTF. */
i2c->cr1 |= I2C_CR1_STOP;
while (i2c->cr1 & I2C_CR1_STOP)
continue;
/* Every 8 rows needs a new page address and hence new I2C transaction. */
p += oled_start_i2c(p);
/* Patch the data bytes onto the end of the address setup sequence. */
memcpy(p, &buffer[128], 128);
p += 128;
i2c_row++;
if (++oled_row == (oled_height / 8)) {
oled_row = 0;
refresh_count++;
}
return p - buffer;
}
static bool_t oled_probe_model(void)
/* Snapshot text buffer into the bitmap buffer. */
static unsigned int oled_prep_buffer(void)
{
uint8_t cmd1[] = { 0x80, 0x00, /* Column 0 */
0xc0 }; /* Read one data */
uint8_t cmd2[] = { 0x80, 0x00, /* Column 0 */
0xc0, 0x00 }; /* Write one data */
uint8_t rsp[2];
int i;
uint8_t x, px = 0;
uint8_t *rand = (uint8_t *)emit8;
for (i = 0; i < 3; i++) {
/* 1st Write stage. */
if (!i2c_sync_write_txn(i2c_addr, cmd1, sizeof(cmd1)))
goto fail;
/* Read stage. */
if (!i2c_sync_read_txn(i2c_addr, rsp, sizeof(rsp)))
goto fail;
x = rsp[1];
/* 2nd Write stage. */
cmd2[3] = x ^ rand[i]; /* XOR the write with "randomness" */
if (!i2c_sync_write_txn(i2c_addr, cmd2, sizeof(cmd2)))
goto fail;
/* Check we read what we wrote on previous iteration. */
if (i && (x != px))
break;
/* Remember what we wrote, for next iteration. */
px = cmd2[3];
}
oled_model = (i == 3) ? OLED_sh1106 : OLED_ssd1306;
printk("OLED: %s\n", (oled_model == OLED_sh1106) ? "SH1106" : "SSD1306");
return TRUE;
fail:
return FALSE;
}
static void oled_init_fast_mode(void)
{
/* Disable I2C (currently in Standard Mode). */
i2c->cr1 = 0;
/* Fast Mode (400kHz). */
i2c->timingr = I2C_TIMING_400k;
return (ff_cfg.display_type & DISPLAY_sh1106)
? sh1106_prep_buffer()
: ssd1306_prep_buffer();
}
static void oled_init(void)
@ -946,6 +692,7 @@ static void oled_init(void)
0xd9, 0xf1, /* pre-charge period */
0xdb, 0x20, /* vcomh detect (default) */
0xa4, /* output follows ram contents */
0xa6, /* normal display output (inverse=off) */
0x2e, /* deactivate scroll */
}, norot_cmds[] = {
0xa1, /* segment mapping (reverse) */
@ -954,21 +701,25 @@ static void oled_init(void)
0xa0, /* segment mapping (default) */
0xc0, /* com scan direction (default) */
};
uint8_t dynamic_cmds[7], *dc;
const uint8_t *cmds;
uint8_t dynamic_cmds[6], *dc;
uint8_t *p = buffer;
if (!(ff_cfg.display_type & DISPLAY_slow))
oled_init_fast_mode();
/* Disable I2C (currently in Standard Mode). */
i2c->cr1 = 0;
if ((oled_model == OLED_unknown) && !oled_probe_model())
goto fail;
/* Fast Mode (400kHz). */
i2c->cr2 = I2C_CR2_FREQ(36);
i2c->ccr = I2C_CCR_FS | I2C_CCR_CCR(30);
i2c->trise = 12;
i2c->cr1 = I2C_CR1_PE;
i2c->cr2 |= I2C_CR2_ITERREN;
/* Initialisation sequence for SSD1306/SH1106. */
p += oled_queue_cmds(p, init_cmds, sizeof(init_cmds));
/* Dynamically-generated initialisation commands. */
dc = dynamic_cmds;
*dc++ = (ff_cfg.display_type & DISPLAY_inverse) ? 0xa7 : 0xa6; /* Video */
*dc++ = 0x81; /* Display Contrast */
*dc++ = ff_cfg.oled_contrast;
*dc++ = 0xa8; /* Multiplex ratio (lcd height - 1) */
@ -977,23 +728,17 @@ static void oled_init(void)
*dc++ = (oled_height == 64) ? 0x12 : 0x02;
p += oled_queue_cmds(p, dynamic_cmds, dc - dynamic_cmds);
/* Display orientation. */
dc = dynamic_cmds;
memcpy(dc, (ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds,
2);
if (ff_cfg.display_type & DISPLAY_hflip)
dc[0] ^= 1;
p += oled_queue_cmds(p, dc, 2);
/* Display is right-way-up, or rotated. */
cmds = (ff_cfg.display_type & DISPLAY_rotate) ? rot_cmds : norot_cmds;
p += oled_queue_cmds(p, cmds, sizeof(rot_cmds));
/* Start off the I2C transaction. */
oled_row = 0;
p += oled_start_i2c(p);
/* Send the initialisation command sequence by DMA. */
i2c->cr2 |= I2C_CR2_DMAEN;
dma_start(p - buffer);
return;
fail:
IRQx_set_pending(I2C_ERROR_IRQ);
}
/*

File diff suppressed because it is too large Load diff

View file

@ -21,15 +21,14 @@
#define CYCLE 8
/* TM1651, 74HC164: DAT = PB10, CLK = PB11 */
static uint8_t DAT_PIN = 10;
static uint8_t CLK_PIN = 11;
#define DAT_PIN 10
#define CLK_PIN 11
/* TM1651, 74HC164: Alphanumeric segment arrangements.
* Bit positions 0-6 correspond to conventional segment labels A-G resp. */
/* TM1651, 74HC164: Alphanumeric segment arrangements. */
static const uint8_t letters[] = {
0x77, 0x7c, 0x58, 0x5e, 0x79, 0x71, 0x6f, 0x74, 0x04, /* a-i */
0x0e, 0x08, 0x38, 0x40, 0x54, 0x5c, 0x73, 0x67, 0x50, /* j-r */
0x6d, 0x78, 0x1c, 0x09, 0x41, 0x76, 0x6e, 0x52 /* s-z */
0x0e, 0x00, 0x38, 0x00, 0x54, 0x5c, 0x73, 0x67, 0x50, /* j-r */
0x6d, 0x78, 0x1c, 0x00, 0x00, 0x76, 0x6e, 0x00 /* s-z */
};
static const uint8_t digits[] = {
@ -131,7 +130,7 @@ static bool_t tm1651_send_cmd(uint8_t cmd)
return fail;
}
static void tm1651_update_display(const uint8_t *d)
static void tm1651_update_display(uint8_t *d)
{
bool_t fail = TRUE;
int retry;
@ -185,7 +184,7 @@ static void shiftreg_update_display_u16(uint16_t x)
static uint16_t shiftreg_curval;
static void shiftreg_update_display(const uint8_t *d)
static void shiftreg_update_display(uint8_t *d)
{
uint16_t x = ((uint16_t)d[0] << 8) | d[1];
shiftreg_curval = x;
@ -221,14 +220,6 @@ void led_7seg_display_setting(bool_t enable)
shiftreg_display_setting(enable);
}
void led_7seg_write_raw(const uint8_t *d)
{
if (nr_digits == 3)
tm1651_update_display(d);
else
shiftreg_update_display(d);
}
void led_7seg_write_string(const char *p)
{
uint8_t d[3] = { 0 }, c;
@ -248,7 +239,10 @@ void led_7seg_write_string(const char *p)
}
}
led_7seg_write_raw(d);
if (nr_digits == 3)
tm1651_update_display(d);
else
shiftreg_update_display(d);
}
void led_7seg_write_decimal(unsigned int val)
@ -262,11 +256,6 @@ void led_7seg_write_decimal(unsigned int val)
void led_7seg_init(void)
{
if (mcu_package == MCU_QFN32) {
DAT_PIN = 6; /* PB6 */
CLK_PIN = 7; /* PB7 */
}
nr_digits = !tm1651_init() ? 3 : 2;
if (nr_digits == 2)
shiftreg_init();

View file

@ -1,5 +1,5 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2019 /
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
@ -9,6 +9,9 @@
extern "C" {
#endif
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
@ -28,8 +31,8 @@ typedef enum {
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
@ -43,11 +46,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14 /
/ FatFs - Generic FAT Filesystem module R0.13 /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2019, ChaN, all right reserved.
/ Copyright (C) 2017, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@ -20,12 +20,13 @@
#ifndef FF_DEFINED
#define FF_DEFINED 86606 /* Revision ID */
#define FF_DEFINED 87030 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
@ -33,30 +34,6 @@ extern "C" {
#endif
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
typedef WORD WCHAR; /* UTF-16 character type */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef unsigned short WORD; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
typedef WORD WCHAR; /* UTF-16 character type */
#endif
/* Definitions of volume management */
@ -65,64 +42,40 @@ typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
/* Type of path name strings on FatFs API */
#if FF_LFN_UNICODE && FF_USE_LFN /* Unicode (UTF-16) string */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
#define _INC_TCHAR
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#define _INC_TCHAR
#endif
#endif
/* Type of file size and LBA variables */
/* Type of file size variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#if !FF_USE_LFN
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#if FF_LBA64
typedef QWORD LBA_t;
#else
typedef DWORD LBA_t;
#endif
#else
#if FF_LBA64
#error exFAT needs to be enabled when enable 64-bit LBA
#endif
typedef DWORD FSIZE_t;
typedef DWORD LBA_t;
#endif
@ -130,8 +83,8 @@ typedef DWORD LBA_t;
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE fs_type; /* Filesystem type (0:N/A) */
BYTE pdrv; /* Physical drive number */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@ -164,15 +117,11 @@ typedef struct {
#endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
LBA_t volbase; /* Volume base sector */
LBA_t volend; /* Volume end sector */
LBA_t fatbase; /* FAT base sector */
LBA_t dirbase; /* Root directory base sector/cluster */
LBA_t database; /* Data base sector */
#if FF_FS_EXFAT
LBA_t bitbase; /* Allocation bitmap base sector */
#endif
LBA_t winsect; /* Current sector appearing in the win[] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
@ -184,7 +133,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
@ -209,9 +158,9 @@ typedef struct {
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !FF_FS_READONLY
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if FF_USE_FASTSEEK
@ -230,7 +179,7 @@ typedef struct {
FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
LBA_t sect; /* Current sector (0:Read operation has terminated) */
DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if FF_USE_LFN
@ -249,31 +198,17 @@ typedef struct {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
BYTE fattrib; /* File attribute */
#if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
TCHAR altname[13]; /* Altenative file name */
TCHAR fname[FF_MAX_LFN + 1]; /* Primary file name */
#else
TCHAR fname[12 + 1]; /* File name */
TCHAR fname[13]; /* File name */
#endif
} FILINFO;
/* Format parameter structure (MKFS_PARM) */
typedef struct {
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
BYTE n_fat; /* Number of FATs */
UINT align; /* Data area alignment (sector) */
UINT n_root; /* Number of root directory entries */
DWORD au_size; /* Cluster size (byte) */
} MKFS_PARM;
/* File function return code (FRESULT) */
typedef enum {
@ -297,13 +232,13 @@ typedef enum {
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */
/* FlashFloppy error codes: */
FR_DISK_FULL = 30, /* (30) Disk full during write */
FR_BAD_IMAGE, /* (31) Bad disk image file */
FR_BAD_HXCSDFE, /* (32) Bad HXCSDFE.CFG file */
FR_BAD_IMAGECFG, /* (33) Bad IMAGE_A.CFG file */
FR_NO_DIRENTS, /* (34) No valid directory entries */
FR_PATH_TOO_DEEP, /* (35) Folders nested too deeply */
/* FlashFloppy error codes: */
FR_DISK_FULL = 30, /* (30) Disk full during write */
FR_BAD_IMAGE, /* (31) Bad disk image file */
FR_BAD_HXCSDFE, /* (32) Bad HXCSDFE.CFG file */
FR_BAD_IMAGECFG, /* (33) Bad IMAGE_A.CFG file */
FR_NO_DIRENTS, /* (34) No valid directory entries */
FR_PATH_TOO_DEEP, /* (35) Folders nested too deeply */
} FRESULT;
@ -336,10 +271,10 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
@ -371,10 +306,10 @@ DWORD get_fattime (void);
#endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
#if FF_USE_LFN /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
WCHAR ff_uni2oem (WCHAR uni, WORD cp); /* Unicode to OEM code conversion */
WCHAR ff_wtoupper (WCHAR uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */

View file

@ -1,14 +1,14 @@
/*---------------------------------------------------------------------------/
/ FatFs Functional Configurations
/ FatFs - Configuration file
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86606 /* Revision ID */
#define FFCONF_DEF 87030 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#if defined(BOOTLOADER)
#if defined(BOOTLOADER) || defined(RELOADER)
#define FF_FS_READONLY 1
#else
#define FF_FS_READONLY 0
@ -19,14 +19,14 @@
/ and optional writing functions as well. */
#if defined(BOOTLOADER)
#if defined(BOOTLOADER) || defined(RELOADER)
#define FF_FS_MINIMIZE 1
#else
#define FF_FS_MINIMIZE 0
#endif
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 0: All basic functions are enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
@ -50,11 +50,7 @@
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#if defined(BOOTLOADER)
#define FF_USE_FASTSEEK 0
#else
#define FF_USE_FASTSEEK 1
#endif
/* This option switches fast seek function. (0:Disable or 1:Enable) */
@ -114,59 +110,40 @@
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
/ specification.
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
/ to the project. The working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional 608 bytes at exFAT enabled. FF_MAX_LFN can be in range from 12 to 255.
/ It should be set 255 to support full featured LFN operations.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
/ ff_memfree(), must be added to the project. */
#define FF_LFN_UNICODE 0
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
/* This option switches character encoding on the API, 0:ANSI/OEM or 1:UTF-16,
/ when LFN is enabled. Also behavior of string I/O functions will be affected by
/ this option. When LFN is not enabled, this option has no effect.
*/
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/* When FF_LFN_UNICODE = 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
/ 0: ANSI/OEM
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8
*/
#if defined(BOOTLOADER)
#define FF_FS_RPATH 0
#else
#define FF_FS_RPATH 1
#endif
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
@ -185,16 +162,11 @@
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
/* FF_STR_VOLUME_ID switches string support for volume ID.
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define FF_MULTI_PARTITION 0
@ -216,27 +188,24 @@
/ GET_SECTOR_SIZE command. */
/* FLASHFLOPPY: Allow GPT partitions to be found. Does not require LBA64,
* nor exFAT. This option alone does not support GPT in f_mkfs. */
#define FF_GPT 1
#define FF_LBA64 0
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
#define FF_MIN_GPT 0x100000000
/* Minimum number of sectors to switch GPT format to create partition in f_mkfs and
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
@ -251,34 +220,22 @@
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ When enable exFAT, also LFN needs to be enabled.
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MON 5
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2019
#define FF_NORTC_YEAR 2017
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_LOCK 0
@ -293,7 +250,6 @@
/ lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
@ -314,6 +270,8 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/

View file

@ -7,7 +7,7 @@
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/*
/ Copyright (C) 2014, ChaN, all right reserved.
/ Copyright (C) 2017, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@ -25,7 +25,7 @@
#include "ff.h"
#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */
#if FF_USE_LFN
#define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -36,7 +36,8 @@
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */
static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
static
const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180,
0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6,
0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE,
@ -963,7 +964,8 @@ static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0
};
static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
static
const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68,
0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70,
0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78,
@ -1892,7 +1894,8 @@ static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
#endif
#if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */
static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
static
const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4,
0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE,
0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9,
@ -4620,7 +4623,8 @@ static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
0, 0
};
static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
static
const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17,
0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F,
0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42,
@ -7350,7 +7354,8 @@ static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
#endif
#if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */
static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
static
const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6,
0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6,
0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF,
@ -9485,7 +9490,8 @@ static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
0, 0
};
static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
static
const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E,
0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25,
0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32,
@ -11622,7 +11628,8 @@ static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
#endif
#if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */
static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
static
const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE,
0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346,
0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E,
@ -13313,7 +13320,8 @@ static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0
};
static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
static
const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A,
0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52,
0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31,
@ -15006,7 +15014,8 @@ static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
#endif
#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0
static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
static
const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15018,7 +15027,8 @@ static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0
static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
static
const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
@ -15030,7 +15040,8 @@ static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0
static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
static
const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
@ -15042,7 +15053,8 @@ static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0
static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
static
const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@ -15054,7 +15066,8 @@ static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0
static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
static
const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
@ -15066,7 +15079,8 @@ static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0
static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
static
const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15078,7 +15092,8 @@ static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0
static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
static
const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
@ -15090,7 +15105,8 @@ static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0
static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
static
const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
@ -15102,7 +15118,8 @@ static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table *
};
#endif
#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0
static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
static
const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15114,7 +15131,8 @@ static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0
static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
static
const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15126,7 +15144,8 @@ static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table
};
#endif
#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0
static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
static
const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15138,7 +15157,8 @@ static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table
};
#endif
#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0
static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
static
const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15150,7 +15170,8 @@ static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0
static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
static
const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
@ -15162,7 +15183,8 @@ static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion
};
#endif
#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0
static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
static
const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
@ -15174,7 +15196,8 @@ static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0
static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
static
const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
@ -15186,7 +15209,8 @@ static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0
static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
static
const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@ -15198,7 +15222,8 @@ static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
};
#endif
#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0
static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
static
const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
@ -15220,7 +15245,7 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WCHAR uni, /* Unicode character to be converted */
WORD cp /* Code page for the conversion */
)
{
@ -15228,20 +15253,19 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
if (uni < 0x80) { /* ASCII char */
c = uni;
} else { /* Non-ASCII */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
} else { /* Non-ASCII char */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */
for (c = 0; c < 0x80 && uni != p[c]; c++) ;
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
@ -15250,7 +15274,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */
if (oem < 0x80) { /* ASCII char */
c = oem;
} else { /* Extended char */
@ -15258,7 +15282,6 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
if (oem < 0x100) c = p[oem - 0x80];
}
}
return c;
}
@ -15271,30 +15294,29 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/* DBCS fixed code page */
/*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE >= 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WCHAR uni, /* Unicode character to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0, uc;
UINT i = 0, n, li, hi;
WCHAR c = 0;
UINT i, n, li, hi;
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
if (uni < 0x80) { /* ASCII char */
c = uni;
} else { /* Non-ASCII */
if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
uc = (WCHAR)uni;
} else { /* Non-ASCII char */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */
p = CVTBL(uni2oem, FF_CODE_PAGE);
hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
if (uni == p[i * 2]) break;
if (uni > p[i * 2]) {
li = i;
} else {
hi = i;
@ -15303,26 +15325,25 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
if (n != 0) c = p[i * 2 + 1];
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0;
UINT i = 0, n, li, hi;
UINT i, n, li, hi;
if (oem < 0x80) { /* ASCII? */
if (oem < 0x80) { /* ASCII char */
c = oem;
} else { /* Extended char */
if (cp == FF_CODE_PAGE) { /* Is it valid code page? */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */
p = CVTBL(oem2uni, FF_CODE_PAGE);
hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1;
li = 0;
@ -15338,7 +15359,6 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
if (n != 0) c = p[i * 2 + 1];
}
}
return c;
}
#endif
@ -15352,63 +15372,11 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
#if FF_CODE_PAGE == 0
static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0};
static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
static const WCHAR *const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0, uc;
UINT i, n, li, hi;
if (uni < 0x80) { /* ASCII? */
c = (WCHAR)uni;
} else { /* Non-ASCII */
if (uni < 0x10000) { /* Is it in BMP? */
uc = (WCHAR)uni;
p = 0;
if (cp < 900) { /* SBCS */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */
p = cp_table[i];
if (p) { /* Is it valid code page ? */
for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */
c = (c + 0x80) & 0xFF;
}
} else { /* DBCS */
switch (cp) { /* Get conversion table */
case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;
case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;
case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;
case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;
}
if (p) { /* Is it valid code page? */
li = 0;
for (n = 16; n; n--) { /* Find OEM code */
i = li + (hi - li) / 2;
if (uc == p[i * 2]) break;
if (uc > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */
WCHAR uni, /* Unicode character to be converted */
WORD cp /* Code page for the conversion */
)
{
@ -15417,7 +15385,55 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
UINT i, n, li, hi;
if (oem < 0x80) { /* ASCII? */
if (uni < 0x80) { /* ASCII char */
c = uni;
} else { /* Non-ASCII char */
p = 0;
if (cp < 900) { /* SBCS */
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */
p = cp_table[i];
if (p) { /* Is it a valid CP ? */
for (c = 0; c < 0x80 && uni != p[c]; c++) ; /* Find OEM code in the table */
c = (c + 0x80) & 0xFF;
}
} else { /* DBCS */
switch (cp) {
case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;
case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;
case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;
case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;
}
if (p) { /* Is it a valid code page? */
li = 0;
for (n = 16; n; n--) { /* Find OEM code */
i = li + (hi - li) / 2;
if (uni == p[i * 2]) break;
if (uni > p[i * 2]) {
li = i;
} else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
}
}
}
return c;
}
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */
WORD cp /* Code page for the conversion */
)
{
const WCHAR *p;
WCHAR c = 0;
UINT i, n, li, hi;
if (oem < 0x80) { /* ASCII char */
c = oem;
} else { /* Extended char */
@ -15450,7 +15466,6 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
}
}
}
return c;
}
#endif
@ -15461,94 +15476,54 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/* Unicode up-case conversion */
/*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */
WCHAR ff_wtoupper ( /* Returns up-converted character */
WCHAR uni /* Unicode character to be upper converted (BMP only) */
)
{
const WORD *p;
WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Compressed upper conversion table */
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */
/* Basic Latin */
0x0061,0x031A,
/* Latin-1 Supplement */
0x00E0,0x0317,
0x00F8,0x0307,
0x00FF,0x0001,0x0178,
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
/* Latin Extended-A */
0x0100,0x0130,
0x0132,0x0106,
0x0139,0x0110,
0x014A,0x012E,
0x0179,0x0106,
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
/* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110,
0x01DD,0x0001,0x018E,
0x01DE,0x0112,
0x01F3,0x0003,0x01F1,0x01F4,0x01F4,
0x01F8,0x0128,
0x0222,0x0112,
0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,
0x0246,0x010A,
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
/* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF,
0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,
0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3,
0x03C4,0x0308,
0x03CC,0x0003,0x038C,0x038E,0x038F,
0x03D8,0x0118,
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */
0x0430,0x0320,
0x0450,0x0710,
0x0460,0x0122,
0x048A,0x0136,
0x04C1,0x010E,
0x04CF,0x0001,0x04C0,
0x04D0,0x0144,
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
/* Armenian */
0x0561,0x0426,
0x0000 /* EOT */
0x0000
};
static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */
/* Phonetic Extensions */
0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */
0x1E00,0x0196,
0x1EA0,0x015A,
0x1E00,0x0196, 0x1EA0,0x015A,
/* Greek Extended */
0x1F00,0x0608,
0x1F10,0x0606,
0x1F20,0x0608,
0x1F30,0x0608,
0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,
0x1F60,0x0608,
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608,
0x1F90,0x0608,
0x1FA0,0x0608,
0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3,
0x1FD0,0x0602,
0x1FE0,0x0602,
0x1FE5,0x0001,0x1FEC,
0x1FF3,0x0001,0x1FFC,
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC,
/* Letterlike Symbols */
0x214E,0x0001,0x2132,
/* Number forms */
0x2170,0x0210,
0x2184,0x0001,0x2183,
0x2170,0x0210, 0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */
0x24D0,0x051A,
0x2C30,0x042F,
0x24D0,0x051A, 0x2C30,0x042F,
/* Latin Extended-C */
0x2C60,0x0102,
0x2C67,0x0106, 0x2C75,0x0102,
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */
0x2C80,0x0164,
/* Georgian Supplement */
@ -15556,38 +15531,36 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
/* Full-width */
0xFF41,0x031A,
0x0000 /* EOT */
0x0000
};
const WCHAR *p;
WCHAR bc, nc, cmd;
if (uni < 0x10000) { /* Is it in BMP? */
uc = (WORD)uni;
p = uc < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get the block base */
if (bc == 0 || uc < bc) break; /* Not matched? */
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (uc < bc + nc) { /* In the block? */
switch (cmd) {
case 0: uc = p[uc - bc]; break; /* Table conversion */
case 1: uc -= (uc - bc) & 1; break; /* Case pairs */
case 2: uc -= 16; break; /* Shift -16 */
case 3: uc -= 32; break; /* Shift -32 */
case 4: uc -= 48; break; /* Shift -48 */
case 5: uc -= 26; break; /* Shift -26 */
case 6: uc += 8; break; /* Shift +8 */
case 7: uc -= 80; break; /* Shift -80 */
case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */
}
break;
p = uni < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get block base */
if (!bc || uni < bc) break;
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (uni < bc + nc) { /* In the block? */
switch (cmd) {
case 0: uni = p[uni - bc]; break; /* Table conversion */
case 1: uni -= (uni - bc) & 1; break; /* Case pairs */
case 2: uni -= 16; break; /* Shift -16 */
case 3: uni -= 32; break; /* Shift -32 */
case 4: uni -= 48; break; /* Shift -48 */
case 5: uni -= 26; break; /* Shift -26 */
case 6: uni += 8; break; /* Shift +8 */
case 7: uni -= 80; break; /* Shift -80 */
case 8: uni -= 0x1C60; break; /* Shift -0x1C60 */
}
if (cmd == 0) p += nc; /* Skip table if needed */
break;
}
uni = uc;
if (!cmd) p += nc;
}
return uni;
}
#endif /* #if FF_USE_LFN */
#endif /* #if _USE_LFN */

38
src/fatfs/integer.h Normal file
View file

@ -0,0 +1,38 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef FF_INTEGER
#define FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

View file

@ -29,11 +29,7 @@ union cfg_slot {
uint16_t words[SLOTW_NR];
};
#if MCU == STM32F105
#define SLOT_BASE (union cfg_slot *)(0x8020000 - FLASH_PAGE_SIZE)
#elif MCU == AT32F435
#define SLOT_BASE (union cfg_slot *)(0x8040000 - FLASH_PAGE_SIZE)
#endif
#define SLOT_NR (FLASH_PAGE_SIZE / sizeof(union cfg_slot))
#define slot_is_blank(_slot) ((_slot)->words[0] == 0xffff)
@ -70,9 +66,9 @@ static union cfg_slot *cfg_slot_find(void)
return NULL;
}
void flash_ff_cfg_update(void *scratch)
void flash_ff_cfg_update(void)
{
union cfg_slot *new_slot = scratch, *slot = cfg_slot_find();
union cfg_slot new_slot, *slot = cfg_slot_find();
uint16_t crc;
/* Nothing to do if Flashed configuration is valid and up to date. */
@ -91,18 +87,16 @@ void flash_ff_cfg_update(void *scratch)
} else {
/* No blank slots available. Erase whole page. */
fpec_page_erase((uint32_t)SLOT_BASE);
if (flash_page_size < FLASH_PAGE_SIZE)
fpec_page_erase((uint32_t)SLOT_BASE + flash_page_size);
slot = SLOT_BASE;
printk("Config: Erased Whole Page\n");
}
memset(new_slot, 0, sizeof(*new_slot));
memcpy(&new_slot->ff_cfg, &ff_cfg, sizeof(ff_cfg));
new_slot->words[SLOTW_DEAD] = 0xffff;
crc = htobe16(crc16_ccitt(new_slot, sizeof(*new_slot)-2, 0xffff));
memset(&new_slot, 0, sizeof(new_slot));
memcpy(&new_slot.ff_cfg, &ff_cfg, sizeof(ff_cfg));
new_slot.words[SLOTW_DEAD] = 0xffff;
crc = htobe16(crc16_ccitt(&new_slot, sizeof(new_slot)-2, 0xffff));
/* Write up to but excluding SLOTW_DEAD. */
fpec_write(new_slot, sizeof(*new_slot)-4, (uint32_t)slot);
fpec_write(&new_slot, sizeof(new_slot)-4, (uint32_t)slot);
/* Write SLOTW_CRC. */
fpec_write(&crc, 2, (uint32_t)&slot->words[SLOTW_CRC]);
printk("Config: Written to Flash Slot %u\n", slot - SLOT_BASE);
@ -120,8 +114,6 @@ void flash_ff_cfg_read(void)
union cfg_slot *slot = cfg_slot_find();
bool_t found = slot_is_valid(slot);
BUILD_BUG_ON(sizeof(*slot) != sizeof(slot->words));
ff_cfg = dfl_ff_cfg;
printk("Config: ");
if (found) {

File diff suppressed because it is too large Load diff

View file

@ -1,739 +0,0 @@
/*
* floppy_generic.c
*
* Generic floppy drive low-level support routines.
* Mainly dealing with IRQs, timers and DMA.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
/* A DMA buffer for running a timer associated with a floppy-data I/O pin. */
struct dma_ring {
/* Current state of DMA (RDATA):
* DMA_inactive: No activity, buffer is empty.
* DMA_starting: Buffer is filling, DMA+timer not yet active.
* DMA_active: DMA is active, timer is operational.
* DMA_stopping: DMA+timer halted, buffer waiting to be cleared.
* Current state of DMA (WDATA):
* DMA_inactive: No activity, flux ring and bitcell buffer are empty.
* DMA_starting: Flux ring and bitcell buffer are filling.
* DMA_active: Writeback processing is active (to mass storage).
* DMA_stopping: Timer halted, buffers waiting to be cleared. */
#define DMA_inactive 0 /* -> {starting, active} */
#define DMA_starting 1 /* -> {active, stopping} */
#define DMA_active 2 /* -> {stopping} */
#define DMA_stopping 3 /* -> {inactive} */
volatile uint8_t state;
/* IRQ handler sets this if the read buffer runs dry. */
volatile uint8_t kick_dma_irq;
/* Indexes into the buf[] ring buffer. */
uint16_t cons;
union {
uint16_t prod; /* dma_rd: our producer index for flux samples */
uint16_t prev_sample; /* dma_wr: previous CCRx sample value */
};
/* DMA ring buffer of timer values (ARR or CCRx). */
uint16_t buf[1024];
};
/* DMA buffers are permanently allocated while a disk image is loaded, allowing
* independent and concurrent management of the RDATA/WDATA pins. */
static struct dma_ring *dma_rd; /* RDATA DMA buffer */
static struct dma_ring *dma_wr; /* WDATA DMA buffer */
/* Statically-allocated floppy drive state. Tracks head movements and
* side changes at all times, even when the drive is empty. */
static struct drive {
uint8_t cyl, head;
bool_t writing;
bool_t sel;
bool_t index_suppressed; /* disable IDX while writing to USB stick */
bool_t amiga_pin34;
uint8_t outp;
volatile bool_t inserted;
struct timer chgrst_timer;
struct {
struct timer timer;
bool_t on;
bool_t changed;
} motor;
struct {
#define STEP_started 1 /* started by hi-pri IRQ */
#define STEP_latched 2 /* latched by lo-pri IRQ */
#define STEP_active (STEP_started | STEP_latched)
#define STEP_settling 4 /* handled by step.timer */
uint8_t state;
bool_t inward;
time_t start;
struct timer timer;
} step;
uint32_t restart_pos;
struct image *image;
} drive;
static struct image *image;
static struct {
struct timer timer, timer_deassert;
time_t prev_time;
bool_t fake_fired;
} index;
static void rdata_stop(void);
static void wdata_start(void);
static void wdata_stop(void);
struct exti_irq {
uint8_t irq, pri;
uint16_t pr_mask; /* != 0: irq- and exti-pending flags are cleared */
};
#if defined(QUICKDISK)
#include "gotek/quickdisk.c"
#define dma_rd_set_active(x) ((void)(x))
#else
#include "gotek/floppy.c"
#endif
/* Initialise IRQs according to statically-defined exti_irqs[]. */
static void floppy_init_irqs(void)
{
const struct exti_irq *e;
unsigned int i;
/* Configure physical interface interrupts. */
for (i = 0, e = exti_irqs; i < ARRAY_SIZE(exti_irqs); i++, e++) {
IRQx_set_prio(e->irq, e->pri);
if (e->pr_mask != 0) {
/* Do not trigger an initial interrupt on this line. Clear EXTI_PR
* before IRQ-pending, otherwise IRQ-pending is immediately
* reasserted. */
exti->pr = e->pr_mask;
IRQx_clear_pending(e->irq);
} else {
/* Common case: we deliberately trigger the first interrupt to
* prime the ISR's state. */
IRQx_set_pending(e->irq);
}
}
/* Enable physical interface interrupts. */
for (i = 0, e = exti_irqs; i < ARRAY_SIZE(exti_irqs); i++, e++) {
IRQx_enable(e->irq);
}
}
/* Allocate and initialise a DMA ring. */
static struct dma_ring *dma_ring_alloc(void)
{
struct dma_ring *dma = arena_alloc(sizeof(*dma));
memset(dma, 0, offsetof(struct dma_ring, buf));
return dma;
}
/* Allocate floppy resources and mount the given image.
* On return: dma_rd, dma_wr, image and index are all valid. */
static void floppy_mount(struct slot *slot)
{
struct image *im;
struct dma_ring *_dma_rd, *_dma_wr;
struct drive *drv = &drive;
FSIZE_t fastseek_sz;
DWORD *cltbl;
FRESULT fr;
int max_ring_kb = (ram_kb >= 128) ? 64 : (ram_kb >= 64) ? 32 : 8;
do {
arena_init();
_dma_rd = dma_ring_alloc();
_dma_wr = dma_ring_alloc();
im = arena_alloc(sizeof(*im));
memset(im, 0, sizeof(*im));
/* Create a fast-seek cluster table for the image. */
#define MAX_FILE_FRAGS 511 /* up to a 4kB cluster table */
cltbl = arena_alloc(0);
*cltbl = (MAX_FILE_FRAGS + 1) * 2;
fatfs_from_slot(&im->fp, slot, FA_READ);
fastseek_sz = f_size(&im->fp);
if (fastseek_sz == 0) {
/* Empty or dummy file. */
cltbl = NULL;
} else {
im->fp.cltbl = cltbl;
fr = f_lseek(&im->fp, CREATE_LINKMAP);
printk("Fast Seek: %u frags\n", (*cltbl / 2) - 1);
if (fr == FR_OK) {
DWORD *_cltbl = arena_alloc(*cltbl * 4);
ASSERT(_cltbl == cltbl);
} else if (fr == FR_NOT_ENOUGH_CORE) {
printk("Fast Seek: FAILED\n");
cltbl = NULL;
} else {
F_die(fr);
}
}
/* ~0 avoids sync match within fewer than 32 bits of scan start. */
im->write_bc_window = ~0;
/* Large buffer to absorb write latencies at mass-storage layer. */
im->bufs.write_bc.len = max_ring_kb*1024; /* power of two */
im->bufs.write_bc.p = arena_alloc(im->bufs.write_bc.len);
/* Read BC buffer overlaps the second half of the write BC buffer. This
* is because:
* (a) The read BC buffer does not need to absorb such large latencies
* (reads are much more predictable than writes to mass storage).
* (b) By dedicating the first half of the write buffer to writes, we
* can safely start processing write flux while read-data is still
* processing (eg. in-flight mass storage io). At say 10kB of
* dedicated write buffer, this is good for >80ms before colliding
* with read buffers, even at HD data rate (1us/bitcell).
* This is more than enough time for read
* processing to complete. */
im->bufs.read_bc.len = im->bufs.write_bc.len / 2;
im->bufs.read_bc.p = (char *)im->bufs.write_bc.p
+ im->bufs.read_bc.len;
/* Any remaining space is used for staging I/O to mass storage, shared
* between read and write paths (Change of use of this memory space is
* fully serialised). */
im->bufs.write_data.len = arena_avail();
im->bufs.write_data.p = arena_alloc(im->bufs.write_data.len);
im->bufs.read_data = im->bufs.write_data;
/* Minimum allowable buffer space. */
ASSERT(im->bufs.read_data.len >= 10*1024);
/* Mount the image file. */
image_open(im, slot, cltbl);
if (!im->disk_handler->write_track || volume_readonly())
slot->attributes |= AM_RDO;
if (slot->attributes & AM_RDO) {
printk("Image is R/O\n");
} else {
image_extend(im);
}
} while (f_size(&im->fp) != fastseek_sz);
/* After image is extended at mount time, we permit no further changes
* to the file metadata. Clear the dirent info to ensure this. */
im->fp.dir_ptr = NULL;
im->fp.dir_sect = 0;
_dma_rd->state = DMA_stopping;
/* Make allocated state globally visible now. */
drv->image = image = im;
barrier(); /* image ptr /then/ dma rings */
dma_rd = _dma_rd;
dma_wr = _dma_wr;
drv->index_suppressed = FALSE;
index.prev_time = time_now();
}
/* Initialise timers and DMA for RDATA/WDATA. */
static void timer_dma_init(void)
{
/* Enable DMA interrupts. */
dma1->ifcr = DMA_IFCR_CGIF(dma_rdata_ch) | DMA_IFCR_CGIF(dma_wdata_ch);
IRQx_set_prio(dma_rdata_irq, RDATA_IRQ_PRI);
IRQx_set_prio(dma_wdata_irq, WDATA_IRQ_PRI);
IRQx_enable(dma_rdata_irq);
IRQx_enable(dma_wdata_irq);
/* RDATA Timer setup:
* The counter is incremented at SAMPLECLK rate.
*
* Ch.2 (RDATA) is in PWM mode 1. It outputs O_TRUE for 400ns and then
* O_FALSE until the counter reloads. By changing the ARR via DMA we alter
* the time between (fixed-width) O_TRUE pulses, mimicking floppy drive
* timings. */
tim_rdata->psc = (SYSCLK_MHZ/SAMPLECLK_MHZ) - 1;
tim_rdata->ccmr1 = (TIM_CCMR1_CC2S(TIM_CCS_OUTPUT) |
TIM_CCMR1_OC2M(TIM_OCM_PWM1));
tim_rdata->ccer = TIM_CCER_CC2E | ((O_TRUE==0) ? TIM_CCER_CC2P : 0);
tim_rdata->ccr2 = sampleclk_ns(400);
tim_rdata->dier = TIM_DIER_UDE;
tim_rdata->cr2 = 0;
/* DMA setup: From a circular buffer into the RDATA Timer's ARR. */
dma_rdata.cpar = (uint32_t)(unsigned long)&tim_rdata->arr;
dma_rdata.cmar = (uint32_t)(unsigned long)dma_rd->buf;
dma_rdata.cndtr = ARRAY_SIZE(dma_rd->buf);
dma_rdata.ccr = (DMA_CCR_PL_HIGH |
DMA_CCR_MSIZE_16BIT |
DMA_CCR_PSIZE_16BIT |
DMA_CCR_MINC |
DMA_CCR_CIRC |
DMA_CCR_DIR_M2P |
DMA_CCR_HTIE |
DMA_CCR_TCIE |
DMA_CCR_EN);
/* WDATA Timer setup:
* The counter runs from 0x0000-0xFFFF inclusive at SAMPLECLK rate.
*
* Ch.1 (WDATA) is in Input Capture mode, sampling on every clock and with
* no input prescaling or filtering. Samples are captured on the falling
* edge of the input (CCxP=1). DMA is used to copy the sample into a ring
* buffer for batch processing in the DMA-completion ISR. */
tim_wdata->psc = (SYSCLK_MHZ/SAMPLECLK_MHZ) - 1;
tim_wdata->arr = 0xffff;
tim_wdata->ccmr1 = TIM_CCMR1_CC1S(TIM_CCS_INPUT_TI1);
tim_wdata->dier = TIM_DIER_CC1DE;
tim_wdata->cr2 = 0;
/* DMA setup: From the WDATA Timer's CCRx into a circular buffer. */
dma_wdata.cpar = (uint32_t)(unsigned long)&tim_wdata->ccr1;
dma_wdata.cmar = (uint32_t)(unsigned long)dma_wr->buf;
dma_wdata.cndtr = ARRAY_SIZE(dma_wr->buf);
dma_wdata.ccr = (DMA_CCR_PL_HIGH |
DMA_CCR_MSIZE_16BIT |
DMA_CCR_PSIZE_16BIT |
DMA_CCR_MINC |
DMA_CCR_CIRC |
DMA_CCR_DIR_P2M |
DMA_CCR_HTIE |
DMA_CCR_TCIE |
DMA_CCR_EN);
}
static unsigned int drive_calc_track(struct drive *drv)
{
return drv->cyl*2 + (drv->head & (drv->image->nr_sides - 1));
}
/* Find current rotational position for read-stream restart. */
static void drive_set_restart_pos(struct drive *drv)
{
uint32_t pos = max_t(int32_t, 0, time_diff(index.prev_time, time_now()));
pos %= drv->image->stk_per_rev;
drv->restart_pos = pos;
drv->index_suppressed = TRUE;
}
/* Called from IRQ context to stop the write stream. */
static void wdata_stop(void)
{
struct write *write;
struct drive *drv = &drive;
uint8_t prev_state = dma_wr->state;
/* Already inactive? Nothing to do. */
if ((prev_state == DMA_inactive) || (prev_state == DMA_stopping))
return;
/* Ok we're now stopping DMA activity. */
dma_wr->state = DMA_stopping;
/* Turn off timer. */
tim_wdata->ccer = 0;
tim_wdata->cr1 = 0;
/* Drain out the DMA buffer. */
IRQx_set_pending(dma_wdata_irq);
switch (ff_cfg.write_drain) {
case WDRAIN_instant:
/* Restart read exactly where write ended. No more IDX pulses until
* write-out is complete. */
drive_set_restart_pos(drv);
break;
case WDRAIN_realtime:
/* Nothing to do. */
break;
case WDRAIN_eot:
/* Position so that an INDEX pulse is quickly triggered. */
drv->restart_pos = drv->image->stk_per_rev - stk_ms(20);
drv->index_suppressed = TRUE;
break;
}
/* Remember where this write's DMA stream ended. */
write = get_write(image, image->wr_prod);
write->dma_end = ARRAY_SIZE(dma_wr->buf) - dma_wdata.cndtr;
image->wr_prod++;
#if !defined(QUICKDISK)
if (!ff_cfg.index_suppression && ff_cfg.write_drain != WDRAIN_realtime) {
/* Opportunistically insert an INDEX pulse ahead of writeback. */
drive_change_output(drv, outp_index, TRUE);
index.fake_fired = TRUE;
IRQx_set_pending(FLOPPY_SOFTIRQ);
/* Position read head so it quickly triggers an INDEX pulse. */
drv->restart_pos = drv->image->stk_per_rev - stk_ms(20);
drv->index_suppressed = TRUE;
}
#endif
}
static void wdata_start(void)
{
struct write *write;
uint32_t start_pos;
switch (dma_wr->state) {
case DMA_starting:
case DMA_active:
/* Already active: ignore WGATE glitch. */
printk("*** WGATE glitch\n");
return;
case DMA_stopping:
if ((image->wr_prod - image->wr_cons) >= ARRAY_SIZE(image->write)) {
/* The write pipeline is full. Complain to the log. */
printk("*** Missed write\n");
return;
}
break;
case DMA_inactive:
/* The write path is quiescent and ready to process this new write. */
break;
}
dma_wr->state = DMA_starting;
/* Start timer. */
tim_wdata->egr = TIM_EGR_UG;
tim_wdata->sr = 0; /* dummy write, gives h/w time to process EGR.UG=1 */
tim_wdata->ccer = TIM_CCER_CC1E | TIM_CCER_CC1P;
tim_wdata->cr1 = TIM_CR1_CEN;
/* Find rotational start position of the write, in SAMPLECLK ticks. */
start_pos = max_t(int32_t, 0, time_diff(index.prev_time, time_now()));
start_pos %= drive.image->stk_per_rev;
start_pos *= SAMPLECLK_MHZ / STK_MHZ;
write = get_write(image, image->wr_prod);
write->start = start_pos;
write->track = drive_calc_track(&drive);
/* Allow IDX pulses while handling a write. */
drive.index_suppressed = FALSE;
/* Exit head-settling state. Ungates INDEX signal. */
cmpxchg(&drive.step.state, STEP_settling, 0);
}
/* Called from IRQ context to stop the read stream. */
static void rdata_stop(void)
{
uint8_t prev_state = dma_rd->state;
/* Already inactive? Nothing to do. */
if (prev_state == DMA_inactive)
return;
/* Ok we're now stopping DMA activity. */
dma_rd->state = DMA_stopping;
dma_rd_set_active(FALSE);
/* If DMA was not yet active, don't need to touch peripherals. */
if (prev_state != DMA_active)
return;
/* Turn off the output pin */
gpio_configure_pin(gpio_data, pin_rdata, GPO_rdata);
/* Turn off timer. */
tim_rdata->cr1 = 0;
/* track-change = instant: Restart read stream where we left off. */
if ((ff_cfg.track_change == TRKCHG_instant)
&& !drive.index_suppressed
&& ff_cfg.index_suppression)
drive_set_restart_pos(&drive);
}
/* Called from user context to start the read stream. */
static void rdata_start(void)
{
IRQ_global_disable();
/* Did we race rdata_stop()? Then bail. */
if (dma_rd->state == DMA_stopping)
goto out;
dma_rd->state = DMA_active;
dma_rd_set_active(TRUE);
/* Start timer. */
tim_rdata->egr = TIM_EGR_UG;
tim_rdata->sr = 0; /* dummy write, gives h/w time to process EGR.UG=1 */
tim_rdata->cr1 = TIM_CR1_CEN;
/* Enable output. */
if (drive.sel)
gpio_configure_pin(gpio_data, pin_rdata, AFO_rdata);
/* Exit head-settling state. Ungates INDEX signal. */
cmpxchg(&drive.step.state, STEP_settling, 0);
out:
IRQ_global_enable();
}
static void floppy_read_data(struct drive *drv)
{
/* Read some track data if there is buffer space. */
if (image_read_track(drv->image) && dma_rd->kick_dma_irq) {
/* We buffered some more data and the DMA handler requested a kick. */
dma_rd->kick_dma_irq = FALSE;
IRQx_set_pending(dma_rdata_irq);
}
}
static bool_t dma_rd_handle(struct drive *drv);
static bool_t dma_wr_handle(struct drive *drv)
{
struct image *im = drv->image;
struct write *write = get_write(im, im->wr_cons);
bool_t completed;
ASSERT((dma_wr->state == DMA_starting) || (dma_wr->state == DMA_stopping));
/* Start a write. */
if (!drv->writing) {
/* Bail out of read mode. */
if (dma_rd->state != DMA_inactive) {
ASSERT(dma_rd->state == DMA_stopping);
if (dma_rd_handle(drv))
return TRUE;
ASSERT(dma_rd->state == DMA_inactive);
}
/* Set up the track for writing. */
if (image_setup_track(im, write->track, NULL))
return TRUE;
drv->writing = TRUE;
}
/* Continue a write. */
completed = image_write_track(im);
/* Is this write now completely processed? */
if (completed) {
/* Clear the staging buffer. */
im->bufs.write_data.cons = 0;
im->bufs.write_data.prod = 0;
/* Align the bitcell consumer index for start of next write. */
im->bufs.write_bc.cons = (write->bc_end + 31) & ~31;
/* Sync back to mass storage. */
F_sync(&im->fp);
IRQ_global_disable();
/* Consume the write from the pipeline buffer. */
im->wr_cons++;
/* If the buffer is empty then reset the write-bitcell ring and return
* to read operation. */
if ((im->wr_cons == im->wr_prod) && (dma_wr->state != DMA_starting)) {
im->bufs.write_bc.cons = im->bufs.write_bc.prod = 0;
dma_wr->state = DMA_inactive;
}
IRQ_global_enable();
/* This particular write is completed. */
drv->writing = FALSE;
}
return FALSE;
}
bool_t floppy_handle(void)
{
struct drive *drv = &drive;
return ((dma_wr->state == DMA_inactive)
? dma_rd_handle : dma_wr_handle)(drv);
}
static void IRQ_rdata_dma(void)
{
const uint16_t buf_mask = ARRAY_SIZE(dma_rd->buf) - 1;
uint32_t prev_ticks_since_index, ticks, i;
uint16_t nr_to_wrap, nr_to_cons, nr, dmacons, done;
time_t now;
struct drive *drv = &drive;
/* Clear DMA peripheral interrupts. */
dma1->ifcr = DMA_IFCR_CGIF(dma_rdata_ch);
/* If we happen to be called in the wrong state, just bail. */
if (dma_rd->state != DMA_active)
return;
/* Find out where the DMA engine's consumer index has got to. */
dmacons = ARRAY_SIZE(dma_rd->buf) - dma_rdata.cndtr;
/* Check for DMA catching up with the producer index (underrun). */
if (((dmacons < dma_rd->cons)
? (dma_rd->prod >= dma_rd->cons) || (dma_rd->prod < dmacons)
: (dma_rd->prod >= dma_rd->cons) && (dma_rd->prod < dmacons))
&& (dmacons != dma_rd->cons))
printk("RDATA underrun! %x-%x-%x\n",
dma_rd->cons, dma_rd->prod, dmacons);
dma_rd->cons = dmacons;
/* Find largest contiguous stretch of ring buffer we can fill. */
nr_to_wrap = ARRAY_SIZE(dma_rd->buf) - dma_rd->prod;
nr_to_cons = (dmacons - dma_rd->prod - 1) & buf_mask;
nr = min(nr_to_wrap, nr_to_cons);
if (nr == 0) /* Buffer already full? Then bail. */
return;
/* Now attempt to fill the contiguous stretch with flux data calculated
* from buffered image data. */
prev_ticks_since_index = image_ticks_since_index(drv->image);
dma_rd->prod += done = image_rdata_flux(
drv->image, &dma_rd->buf[dma_rd->prod], nr);
dma_rd->prod &= buf_mask;
if (done != nr) {
/* Read buffer ran dry: kick us when more data is available. */
dma_rd->kick_dma_irq = TRUE;
} else if (nr != nr_to_cons) {
/* We didn't fill the ring: re-enter this ISR to do more work. */
IRQx_set_pending(dma_rdata_irq);
}
/* Check if we have crossed the index mark. If not, we're done. */
if (image_ticks_since_index(drv->image) >= prev_ticks_since_index)
return;
/* We crossed the index mark: Synchronise index pulse to the bitstream. */
for (;;) {
/* Snapshot current position in flux stream, including progress through
* current timer sample. */
now = time_now();
/* Ticks left in current sample. */
ticks = tim_rdata->arr - tim_rdata->cnt;
/* Index of next sample. */
dmacons = ARRAY_SIZE(dma_rd->buf) - dma_rdata.cndtr;
/* If another sample was loaded meanwhile, try again for a consistent
* snapshot. */
if (dmacons == dma_rd->cons)
break;
dma_rd->cons = dmacons;
}
/* Sum all flux timings in the DMA buffer. */
for (i = dmacons; i != dma_rd->prod; i = (i+1) & buf_mask)
ticks += dma_rd->buf[i] + 1;
/* Subtract current flux offset beyond the index. */
ticks -= image_ticks_since_index(drv->image);
/* Calculate deadline for index timer. */
ticks /= SAMPLECLK_MHZ/TIME_MHZ;
timer_set(&index.timer, now + ticks);
}
static void IRQ_wdata_dma(void)
{
const uint16_t buf_mask = ARRAY_SIZE(dma_rd->buf) - 1;
uint16_t cons, prod, prev, next;
uint32_t bc_dat = 0, bc_prod;
uint32_t *bc_buf = image->bufs.write_bc.p;
unsigned int sync = image->sync;
unsigned int bc_bufmask = (image->bufs.write_bc.len / 4) - 1;
int curr, cell = image->write_bc_ticks;
struct write *write = NULL;
/* Clear DMA peripheral interrupts. */
dma1->ifcr = DMA_IFCR_CGIF(dma_wdata_ch);
/* If we happen to be called in the wrong state, just bail. */
if (dma_wr->state == DMA_inactive)
return;
/* Find out where the DMA engine's producer index has got to. */
prod = ARRAY_SIZE(dma_wr->buf) - dma_wdata.cndtr;
/* Check if we are processing the tail end of a write. */
barrier(); /* interrogate peripheral /then/ check for write-end. */
if (image->wr_bc != image->wr_prod) {
write = get_write(image, image->wr_bc);
prod = write->dma_end;
}
/* Process the flux timings into the raw bitcell buffer. */
prev = dma_wr->prev_sample;
bc_prod = image->bufs.write_bc.prod;
bc_dat = image->write_bc_window;
for (cons = dma_wr->cons; cons != prod; cons = (cons+1) & buf_mask) {
next = dma_wr->buf[cons];
curr = (int16_t)(next - prev) - (cell >> 1);
if (unlikely(curr < 0)) {
/* Runt flux, much shorter than bitcell clock. Merge it forward. */
continue;
}
prev = next;
while ((curr -= cell) > 0) {
bc_dat <<= 1;
bc_prod++;
if (!(bc_prod&31))
bc_buf[((bc_prod-1) / 32) & bc_bufmask] = htobe32(bc_dat);
}
curr += cell >> 1; /* remove the 1/2-cell bias */
prev -= curr >> 2; /* de-jitter/precomp: carry 1/4 of phase error */
bc_dat = (bc_dat << 1) | 1;
bc_prod++;
switch (sync) {
case SYNC_fm:
/* FM clock sync clock byte is 0xc7. Check for:
* 1010 1010 1010 1010 1x1x 0x0x 0x1x 1x1x */
if ((bc_dat & 0xffffd555) == 0x55555015)
bc_prod = (bc_prod - 31) | 31;
break;
case SYNC_mfm:
if (bc_dat == 0x44894489)
bc_prod &= ~31;
break;
}
if (!(bc_prod&31))
bc_buf[((bc_prod-1) / 32) & bc_bufmask] = htobe32(bc_dat);
}
if (bc_prod & 31)
bc_buf[(bc_prod / 32) & bc_bufmask] = htobe32(bc_dat << (-bc_prod&31));
/* Processing the tail end of a write? */
if (write != NULL) {
/* Remember where this write's bitcell data ends. */
write->bc_end = bc_prod;
if (++image->wr_bc != image->wr_prod)
IRQx_set_pending(dma_wdata_irq);
/* Initialise decoder state for the start of the next write. */
bc_prod = (bc_prod + 31) & ~31;
bc_dat = ~0;
prev = 0;
}
/* Save our progress for next time. */
image->write_bc_window = bc_dat;
image->bufs.write_bc.prod = bc_prod;
dma_wr->cons = cons;
dma_wr->prev_sample = prev;
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -1,5 +1,5 @@
/*
* fpec_stm32f105.c
* fpec.c
*
* STM32F10x Flash Memory Program/Erase Controller (FPEC).
*

View file

@ -1,62 +0,0 @@
/*
* fpec_at324f435.c
*
* AT32F435 Flash Memory Program/Erase Controller (FPEC).
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
static void fpec_wait_and_clear(FLASH_BANK bank)
{
while (bank->sr & FLASH_SR_BSY)
continue;
bank->sr = FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR;
bank->cr = 0;
}
void fpec_init(void)
{
/* Unlock the FPEC. */
if (flash->bank1.cr & FLASH_CR_LOCK) {
flash->unlock1 = 0x45670123;
flash->unlock1 = 0xcdef89ab;
}
fpec_wait_and_clear(&flash->bank1);
}
void fpec_page_erase(uint32_t flash_address)
{
FLASH_BANK bank = &flash->bank1;
fpec_wait_and_clear(bank);
bank->ar = flash_address;
bank->cr |= FLASH_CR_PG_ER | FLASH_CR_ERASE_STRT;
fpec_wait_and_clear(bank);
}
void fpec_write(const void *data, unsigned int size, uint32_t flash_address)
{
FLASH_BANK bank = &flash->bank1;
uint16_t *_f = (uint16_t *)flash_address;
const uint16_t *_d = data;
fpec_wait_and_clear(bank);
for (; size != 0; size -= 2) {
bank->cr |= FLASH_CR_PG;
*_f++ = *_d++;
fpec_wait_and_clear(bank);
}
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/

View file

@ -124,7 +124,7 @@ void F_truncate(FIL *fp)
#endif /* !FF_FS_READONLY */
void F_lseek(FIL *fp, FSIZE_t ofs)
void F_lseek(FIL *fp, DWORD ofs)
{
FRESULT fr;
#if !FF_FS_READONLY
@ -168,13 +168,11 @@ void F_findnext(DIR *dp, FILINFO *fno)
handle_fr(fr);
}
#if !defined(BOOTLOADER)
void F_chdir(const TCHAR *path)
{
FRESULT fr = f_chdir(path);
handle_fr(fr);
}
#endif
/*
* Local variables:

View file

@ -3,63 +3,12 @@
*
* Gotek board-specific setup and management.
*
* SFRC922, SFRC922C, SFRC922D et al
* Original LQFP64 designs, using STM or AT chips.
* Buttons: PC6 = Select, PC7 = Right, PC8 = Left
* Rotary: PC10, PC11
*
* SFRC922AT3
* LQFP48 design, missing rotary header.
* Alternative rotary location at PA13, PA14
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
*
* SFRKC30AT4, SFRKC30.AT4, SFRKC30.AT4.7 (KC30 Rev 1)
* LQFP64 designs with original rotary header and "KC30" rotary header.
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
* Rotary: PC10, PC11
* KC30: PF6/PH2 = Select, PA6/PA15 = Rotary
*
* SFRKC30AT3 (KC30 Rev 1)
* LQFP48 design similar to SFRC922AT3 but with the "KC30" rotary header.
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
* KC30: PF6/PH2 = Select, PA6/PA15 = Rotary
*
* SFRKC30.AT2 (KC30 Rev 1)
* QFN32 design with various pin changes and features missing. There are
* two versions; the newer version reintroduces jumper position JC.
* Missing:
* * Original rotary header
* * JC jumper position (old version)
* Relocated to new MCU pins:
* * Display header is moved to PB[7:6] using I2C1 instead of I2C2
* * KC30 header SELECT/button pin
* * Floppy output pins 2 and 26
* * Floppy WGATE input pin
* * JC jumper at PA9 (new version)
* Buttons: PA5 = Select, PA4 = Right, PA3 = Left
* KC30: PA10 = Select, PA6/PA15 = Rotary
*
* SFRKC30.AT4.35 (KC30 Rev 2)
* As SFRKC30.AT4 except PC15 is tied HIGH for identification.
* MOTOR (pin 16) is optionally jumpered to PB12 with 1k pullup to 5v.
*
* Written & released by Keir Fraser <keir.xen@gmail.com>
*
* This is free and unencumbered software released into the public domain.
* See the file COPYING for more details, or visit <http://unlicense.org>.
*/
uint8_t mcu_package;
uint8_t has_kc30_header;
#if MCU == STM32F105
#define kc30_sel_gpio gpiof
#define kc30_sel_pin 6
#elif MCU == AT32F435
#define kc30_sel_gpio gpioh
#define kc30_sel_pin 2
#endif
/* Pull up currently unused and possibly-floating pins. */
static void gpio_pull_up_pins(GPIO gpio, uint16_t mask)
{
@ -71,115 +20,13 @@ static void gpio_pull_up_pins(GPIO gpio, uint16_t mask)
}
}
unsigned int board_get_buttons(void)
{
/* All recent Gotek revisions, regardless of MCU model or package:
* PA5 = Select, PA4 = Right, PA3 = Left.
* Note: "Enhanced Gotek" design uses these pins so must skip them here. */
unsigned int x = (board_id == BRDREV_Gotek_standard)
? gpioa->idr >> 3 : -1;
/* Earlier Gotek revisions (all of which are LQFP64):
* PC6 = Select, PC7 = Right, PC8 = Left. */
if (mcu_package == MCU_LQFP64)
x &= _rbit32(gpioc->idr) >> 23;
x = ~x & 7;
if (has_kc30_header) {
/* KC30 Select pin, Artery models only:
* PF6/PH2 = Select; except QFN32: PA10 = Select. */
unsigned int kc30 = (mcu_package == MCU_QFN32
? gpioa->idr >> (10-2) /* PA10 */
: kc30_sel_gpio->idr >> (kc30_sel_pin-2));
x |= ~kc30 & 4;
}
return x;
}
unsigned int board_get_rotary(void)
{
unsigned int x = 3;
if ((mcu_package != MCU_QFN32) && (ff_cfg.chgrst != CHGRST_pa14)) {
/* Alternative location at PA13, PA14. */
x &= gpioa->idr >> 13;
}
if (mcu_package == MCU_LQFP64) {
/* Original rotary header at PC10, PC11. */
x &= gpioc->idr >> 10;
}
if (has_kc30_header) {
/* KC30 rotary pins PA6, PA15. */
unsigned int kc30 = gpioa->idr;
kc30 = ((kc30>>6)&1) | ((kc30>>(15-1))&2);
x &= kc30;
}
return x;
}
uint32_t board_rotary_exti_mask;
void board_setup_rotary_exti(void)
{
uint32_t m = 0;
if ((mcu_package != MCU_QFN32) && (ff_cfg.chgrst != CHGRST_pa14)) {
/* Alternative location at PA13, PA14. */
exti_route_pa(13);
exti_route_pa(14);
m |= m(13) | m(14);
}
if (mcu_package == MCU_LQFP64) {
/* Original rotary header at PC10, PC11. */
exti_route_pc(10);
exti_route_pc(11);
m |= m(10) | m(11);
}
if (((has_kc30_header == 1) && (ff_cfg.motor_delay == MOTOR_ignore))
|| (has_kc30_header == 2) /* No conflict with motor on PB12 */) {
/* KC30 rotary pins PA6, PA15. */
exti_route_pa(6);
exti_route_pa(15);
m |= m(6) | m(15);
}
board_rotary_exti_mask = m;
exti->rtsr |= m;
exti->ftsr |= m;
exti->imr |= m;
}
void board_jc_set_mode(unsigned int mode)
{
if (mcu_package == MCU_QFN32) {
#if !defined(NDEBUG)
/* PA9 is used for serial tx */
#else
gpio_configure_pin(gpioa, 9, mode);
#endif
} else {
gpio_configure_pin(gpiob, 1, mode);
}
}
bool_t board_jc_strapped(void)
{
if (mcu_package == MCU_QFN32) {
#if !defined(NDEBUG)
return FALSE; /* PA9 is used for serial tx */
#else
return !gpio_read_pin(gpioa, 9);
#endif
}
return !gpio_read_pin(gpiob, 1);
}
void board_init(void)
{
uint16_t pa_skip, pb_skip, pc_skip;
uint16_t pa_skip, pb_skip;
uint8_t id;
/* PA0-1,8 (floppy inputs), PA2 (speaker). */
pa_skip = 0x0107;
#if !defined(NDEBUG)
/* PA9-10 (serial console). */
pa_skip |= 0x0600;
#endif
/* PA0-1,8 (floppy inputs), PA2 (speaker), PA9-10 (serial console). */
pa_skip = 0x0707;
/* PB0,4,9 (floppy inputs). */
pb_skip = 0x0211;
@ -190,95 +37,24 @@ void board_init(void)
gpio_configure_pin(gpioa, 12, GPI_pull_down);
/* Pull up all PCx pins. */
pc_skip = 0x0000;
gpio_pull_up_pins(gpioc, ~pc_skip);
gpio_pull_up_pins(gpioc, ~0x0000);
/* Wait for ID to stabilise at PC[15:12]. */
delay_us(100);
delay_us(5);
id = (gpioc->idr >> 12) & 0xf;
if (is_artery_mcu) {
switch (dbg->mcu_idcode & 0xfff) {
case 0x1c6: /* AT32F415KBU7-4 */
case 0x242: /* AT32F415KCU7-4 */
mcu_package = MCU_QFN32;
id = 0xf;
break;
}
}
if (is_artery_mcu && (id & 2)) {
/* This is a factory Gotek board design, or direct clone, with an
* Artery MCU. We now check which factory design: variants exist for
* 48- and 64-pin Artery MCUs, and with various headers for buttons and
* rotary encoders. Though we have discriminated on PC13 alone, the
* only expected ID values here are 1110 (48-pin MCU) and 1111 (64-pin
* MCU). */
board_id = BRDREV_Gotek_standard;
if (mcu_package == MCU_QFN32) {
/* The sole QFN32 board is a KC30 Rev 1 design. */
has_kc30_header = 1;
pa_skip &= ~(1<<10); /* PA10 is not used as serial rx */
pb_skip |= 1<<1; /* PB1 is a floppy input (WGATE) */
} else {
/* 48-pin package has PC12 permanently LOW. */
if (!(id & 1))
mcu_package = MCU_LQFP48;
/* Check for KC30 Rev 2. */
gpio_configure_pin(gpioc, 15, GPI_pull_down);
delay_us(100);
if (gpio_read_pin(gpioc, 15) == HIGH) {
/* KC30 Rev 2. */
has_kc30_header = 2;
pb_skip |= 1<<12; /* PB12 is a floppy input (MOTOR) */
} else {
/* If PF7 is floating then we are running on a board with the
* optional rotary-encoder header (SFRKC30 Rev 1). On earlier
* boards PF6=VSS and PF7=VDD, hence we take care here. */
#if MCU == STM32F105 /* Only AT32F415 has the PF7 pin. */
rcc->apb2enr |= RCC_APB2ENR_IOPFEN;
gpio_configure_pin(gpiof, 7, GPI_pull_down);
delay_us(100);
if (gpio_read_pin(gpiof, 7) == LOW) {
/* KC30 Rev 1. */
has_kc30_header = 1;
}
gpio_configure_pin(gpiof, 7, GPI_floating);
#endif
}
}
if (has_kc30_header)
gpio_configure_pin(kc30_sel_gpio, kc30_sel_pin, GPI_pull_up);
} else {
switch (board_id = id) {
case BRDREV_Gotek_standard:
break;
case BRDREV_Gotek_enhanced:
case BRDREV_Gotek_sd_card:
/* PA3,15 (floppy inputs), PA4 (USBENA). */
pa_skip |= 0x8018;
/* PA4: /USBENA */
gpio_configure_pin(gpioa, 4, GPO_pushpull(_2MHz, LOW));
break;
default:
ASSERT(0);
}
switch (board_id = id) {
case BRDREV_Gotek_standard:
break;
case BRDREV_Gotek_enhanced:
case BRDREV_Gotek_sd_card:
/* PA3,15 (floppy inputs), PA4 (USBENA). */
pa_skip |= 0x8018;
/* PA4: /USBENA */
gpio_configure_pin(gpioa, 4, GPO_pushpull(_2MHz, LOW));
break;
default:
ASSERT(0);
}
gpio_pull_up_pins(gpioa, ~pa_skip);

View file

@ -13,71 +13,51 @@
#define O_TRUE 0
/* Input pins: DIR=PB0, STEP=PA1, SELA=PA0, SELB=PA3, WGATE=PB9, SIDE=PB4,
* MOTOR=PA15/PB15 */
* MOTOR=PA15 */
#define pin_dir 0 /* PB0 */
#define pin_step 1 /* PA1 */
#define pin_sel0 0 /* PA0 */
#define pin_sel1 3 /* PA3 */
static uint8_t pin_wgate = 9; /* PB9 */
#define pin_wgate 9 /* PB9 */
#define pin_side 4 /* PB4 */
static uint8_t pin_motor = 15; /* PA15 or PB15 */
#define pin_chgrst 14 /* PA14 if CHGRST_pa14 */
#define pin_motor 15 /* PA15 */
/* Output pins. PBx = 0-15, PAx = 16-31. */
static uint8_t pin_02 = 7; /* PB7 */
#define pin_08 8 /* PB8 */
static uint8_t pin_26 = 6; /* PB6 */
#define pin_28 5 /* PB5 */
#define pin_34 3 /* PB3 */
/* Output pins. */
#define gpio_out gpiob
#define pin_02 7
#define pin_08 8
#define pin_26 6
#define pin_28 5
#define pin_34 3
#define gpio_data gpioa
#define pin_wdata 8
#define tim_wdata (tim1)
#define dma_wdata (dma1->ch[2-1])
#define dma_wdata (dma1->ch2)
#define dma_wdata_ch 2
#define dma_wdata_irq DMA1_CH2_IRQ
DEFINE_IRQ(dma_wdata_irq, "IRQ_wdata_dma");
#define dma_wdata_irq 12
void IRQ_12(void) __attribute__((alias("IRQ_wdata_dma")));
#define pin_rdata 7
#define tim_rdata (tim3)
#define dma_rdata (dma1->ch[3-1])
#define dma_rdata (dma1->ch3)
#define dma_rdata_ch 3
#define dma_rdata_irq DMA1_CH3_IRQ
DEFINE_IRQ(dma_rdata_irq, "IRQ_rdata_dma");
#define dma_rdata_irq 13
void IRQ_13(void) __attribute__((alias("IRQ_rdata_dma")));
/* EXTI IRQs. */
void IRQ_6(void) __attribute__((alias("IRQ_SELA_changed"))); /* EXTI0 */
void IRQ_7(void) __attribute__((alias("IRQ_WGATE_rotary"))); /* EXTI1 */
/*void IRQ_6(void) __attribute__((alias("IRQ_SELA_changed")));*/ /* EXTI0 */
void IRQ_7(void) __attribute__((alias("IRQ_STEP_changed"))); /* EXTI1 */
void IRQ_10(void) __attribute__((alias("IRQ_SIDE_changed"))); /* EXTI4 */
void IRQ_23(void) __attribute__((alias("IRQ_WGATE_rotary"))); /* EXTI9_5 */
void IRQ_28(void) __attribute__((alias("IRQ_STEP_changed"))); /* TMR2 */
void IRQ_40(void) __attribute__((alias("IRQ_MOTOR_CHGRST_rotary"))); /* EXTI15_10 */
#define MOTOR_CHGRST_IRQ 40
void IRQ_23(void) __attribute__((alias("IRQ_WGATE_changed"))); /* EXTI9_5 */
static const struct exti_irq exti_irqs[] = {
/* SELA */ { 6, FLOPPY_IRQ_SEL_PRI, 0 },
/* STEP */ { 28, FLOPPY_IRQ_STEP_PRI, m(2) /* dummy */ },
/* WGATE */ { 7, FLOPPY_IRQ_WGATE_PRI, 0 },
/* SIDE */ { 10, TIMER_IRQ_PRI, 0 },
/* WGATE */ { 23, FLOPPY_IRQ_WGATE_PRI, 0 },
/* MTR/CHGRST */ { 40, TIMER_IRQ_PRI, 0 }
{ 6, FLOPPY_IRQ_SEL_PRI, 0 },
{ 7, FLOPPY_IRQ_STEP_PRI, m(pin_step) },
{ 10, FLOPPY_IRQ_SIDE_PRI, 0 },
{ 23, FLOPPY_IRQ_WGATE_PRI, 0 }
};
/* Subset of output pins which are active (O_TRUE). */
extern uint32_t gpio_out_active;
/* Abuse gpio_out_active:PA11 to indicate that read DMA is active. This is
* safe because PA11 is configured for USB, so GPIO level has no effect.
* This saves some memory loads in the critical SELA IRQ handler. */
#define GPIO_OUT_DMA_RD_ACTIVE (16+11)
/* GPIO register to either assert or deassert active output pins. */
extern uint32_t gpiob_setreset;
/* This bitband address is used to atomically update GPIO_OUT_DMA_RD_ACTIVE */
static volatile uint32_t *p_dma_rd_active;
#define dma_rd_set_active(x) (*p_dma_rd_active = (x))
bool_t floppy_ribbon_is_reversed(void)
{
time_t t_start = time_now();
@ -95,89 +75,24 @@ bool_t floppy_ribbon_is_reversed(void)
return FALSE;
}
static uint32_t *get_bitband(void *ram_addr, unsigned int bit)
{
uint32_t byte = (uint32_t)ram_addr - 0x20000000u;
return (uint32_t *)(0x22000000u + (byte * 32) + (bit * 4));
}
static void board_floppy_init(void)
{
p_dma_rd_active = get_bitband(&gpio_out_active, GPIO_OUT_DMA_RD_ACTIVE);
#if MCU == STM32F105
#define change_pin_mode(gpio, pin, mode) \
gpio->crl = (gpio->crl & ~(0xfu<<((pin)<<2))) \
| (((mode)&0xfu)<<((pin)<<2))
gpio_configure_pin(gpioa, pin_step, GPI_bus);
gpio_configure_pin(gpio_data, pin_wdata, GPI_bus);
gpio_configure_pin(gpio_data, pin_rdata, GPO_bus);
#elif MCU == AT32F435
#define change_pin_mode(gpio, pin, mode) \
gpio->moder = (gpio->moder & ~(0x3u<<((pin)<<1))) \
| (((mode)&0x3u)<<((pin)<<1));
#define afio syscfg
gpio_set_af(gpioa, pin_step, 1);
gpio_configure_pin(gpioa, pin_step, AFI(PUPD_none));
gpio_set_af(gpio_data, pin_wdata, 1);
gpio_configure_pin(gpio_data, pin_wdata, AFI(PUPD_none));
gpio_set_af(gpio_data, pin_rdata, 2);
gpio_configure_pin(gpio_data, pin_rdata, GPO_bus);
dmamux1->cctrl[dma_wdata_ch-1] = DMAMUX_CCTRL_REQSEL(DMAMUX_REQ_TIM1_CH1);
dmamux1->cctrl[dma_rdata_ch-1] = DMAMUX_CCTRL_REQSEL(DMAMUX_REQ_TIM3_OVF);
#endif
/* PA1 (STEP) triggers IRQ via TIM2 Channel 2, since EXTI is used for
* WGATE on PB1. */
tim2->ccmr1 = TIM_CCMR1_CC2S(TIM_CCS_INPUT_TI1);
tim2->ccer = TIM_CCER_CC2E;
tim2->dier = TIM_DIER_CC2IE;
tim2->cr1 = TIM_CR1_CEN;
if (mcu_package == MCU_QFN32) {
pin_02 = 16 + 14; /* PA14 */
pin_26 = 16 + 13; /* PA13 */
pin_wgate = 1; /* PB1 */
}
gpio_configure_pin(gpiob, pin_dir, GPI_bus);
gpio_configure_pin(gpioa, pin_step, GPI_bus);
gpio_configure_pin(gpioa, pin_sel0, GPI_bus);
gpio_configure_pin(gpiob, pin_wgate, GPI_bus);
gpio_configure_pin(gpiob, pin_side, GPI_bus);
/* PA[15:13], PB[12], PC[11:10], PB[9:1], PA[0] */
afio->exticr[4-1] = 0x0001;
afio->exticr[3-1] = 0x2211;
afio->exticr[2-1] = 0x1111;
afio->exticr[1-1] = 0x1110;
if (gotek_enhanced()) {
gpio_configure_pin(gpioa, pin_sel1, GPI_bus);
gpio_configure_pin(gpioa, pin_motor, GPI_bus);
} else if (has_kc30_header == 2) {
pin_motor = 12; /* PB12 */
} else {
/* This gives us "motor always on" if the pin is not connected.
* It is safe enough to pull down even if connected direct to 5v,
* will only sink ~0.15mA via the weak internal pulldown. */
gpio_configure_pin(gpiob, pin_motor, GPI_pull_down);
exti_route_pb(15); /* Motor = PB15 */
}
exti->rtsr = 0xffff;
exti->ftsr = 0xffff;
exti->imr = m(pin_wgate) | m(pin_side) | m(pin_sel0);
/* PB[15:2] -> EXT[15:2], PA[1:0] -> EXT[1:0] */
afio->exticr2 = afio->exticr3 = afio->exticr4 = 0x1111;
afio->exticr1 = 0x1100;
gpiob_setreset = (uint32_t)&gpiob->bsrr;
exti->imr = exti->rtsr = exti->ftsr =
m(pin_wgate) | m(pin_side) | m(pin_step) | m(pin_sel0);
}
/* Fast speculative entry point for SELA-changed IRQ. We assume SELA has
@ -186,32 +101,40 @@ static void board_floppy_init(void)
* Note that the entirety of the SELA handler is in SRAM (.data) -- not only
* is this faster to execute, but allows us to co-locate gpio_out_active for
* even faster access in the time-critical speculative entry point. */
__attribute__((naked)) __attribute__((section(".ramfuncs"))) aligned(4)
void IRQ_SELA_changed(void) {
asm (
".global gpio_out_active, gpiob_setreset\n"
" ldr r0, [pc, #8]\n" /* r0 = gpio_out_active */
" ldr r1, [pc, #12]\n" /* r1 = &gpiob->b[s]rr */
" uxth r2, r0\n" /* r2 = (uint16_t)gpio_out_active */
" str r2, [r1, #0]\n" /* gpiob->b[s]rr = gpio_out_active */
" b.n _IRQ_SELA_changed\n" /* branch to the main ISR entry point */
" nop\n"
"gpio_out_active: .word 0\n"
"gpiob_setreset: .word 0\n" /* gpiob->b[s]rr */
);
}
void IRQ_SELA_changed(void);
asm (
" .data\n"
" .align 4\n"
" .thumb_func\n"
" .type IRQ_SELA_changed,%function\n"
"IRQ_SELA_changed:\n"
" ldr r0, [pc, #4]\n" /* r0 = gpio_out_active */
" ldr r1, [pc, #8]\n" /* r1 = &gpio_out->b[s]rr */
" str r0, [r1, #0]\n" /* gpio_out->b[s]rr = gpio_out_active */
" b.n _IRQ_SELA_changed\n" /* branch to the main ISR entry point */
"gpio_out_active: .word 0\n"
"gpio_out_setreset: .word 0x40010c10\n" /* gpio_out->b[s]rr */
" .global IRQ_6\n"
" .thumb_set IRQ_6,IRQ_SELA_changed\n"
" .previous\n"
);
static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
__attribute__((used)) __attribute__((section(".ramfuncs")));
/* Subset of output pins which are active (O_TRUE). */
extern uint32_t gpio_out_active;
/* GPIO register to either assert or deassert active output pins. */
extern uint32_t gpio_out_setreset;
static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpio_out_setreset)
__attribute__((used)) __attribute__((section(".data@")));
static void _IRQ_SELA_changed(uint32_t _gpio_out_active)
__attribute__((used)) __attribute__((section(".ramfuncs")))
__attribute__((optimize("Ofast")));
__attribute__((used)) __attribute__((section(".data@")));
/* Intermediate SELA-changed handler for generating the Amiga HD RDY signal. */
static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpio_out_setreset)
{
/* If deasserting the bus, toggle pin 34 for next time we take the bus. */
if ((uint8_t)_gpiob_setreset == (uint8_t)(uint32_t)&gpiob->bsrr)
if (!(_gpio_out_setreset & 4))
gpio_out_active ^= m(pin_34);
/* Continue to the main SELA-changed IRQ entry point. */
@ -223,37 +146,42 @@ static void Amiga_HD_ID(uint32_t _gpio_out_active, uint32_t _gpiob_setreset)
* speculative entry point for the next interrupt. */
static void _IRQ_SELA_changed(uint32_t _gpio_out_active)
{
/* Latch SELA. */
/* Clear SELA-changed flag. */
exti->pr = m(pin_sel0);
drive.sel = !(gpioa->idr & m(pin_sel0));
if (drive.sel) {
if (!(gpioa->idr & m(pin_sel0))) {
/* SELA is asserted (this drive is selected).
* Immediately re-enable all our asserted outputs. */
gpiob->brr = _gpio_out_active & 0xffff;
gpioa->brr = _gpio_out_active >> 16;
gpio_out->brr = _gpio_out_active;
/* Set pin_rdata as timer output (AFO_bus). */
if (_gpio_out_active & m(GPIO_OUT_DMA_RD_ACTIVE))
change_pin_mode(gpio_data, pin_rdata, AFO_bus);
/* Speculate that, on next interrupt, SELA is deasserted. */
*(uint8_t *)&gpiob_setreset = (uint8_t)(uint32_t)&gpiob->bsrr;
if (dma_rd && (dma_rd->state == DMA_active))
gpio_data->crl = (gpio_data->crl & ~(0xfu<<(pin_rdata<<2)))
| ((AFO_bus&0xfu)<<(pin_rdata<<2));
/* Let main code know it can drive the bus until further notice. */
drive.sel = 1;
} else {
/* SELA is deasserted (this drive is not selected).
* Relinquish the bus by disabling all our asserted outputs. */
gpiob->bsrr = _gpio_out_active & 0xffff;
gpioa->bsrr = _gpio_out_active >> 16;
gpio_out->bsrr = _gpio_out_active;
/* Set pin_rdata as quiescent (GPO_bus). */
change_pin_mode(gpio_data, pin_rdata, GPO_bus);
/* Speculate that, on next interrupt, SELA is asserted. */
*(uint8_t *)&gpiob_setreset = (uint8_t)(uint32_t)&gpiob->brr;
if (dma_rd && (dma_rd->state == DMA_active))
gpio_data->crl = (gpio_data->crl & ~(0xfu<<(pin_rdata<<2)))
| ((GPO_bus&0xfu)<<(pin_rdata<<2));
/* Tell main code to leave the bus alone. */
drive.sel = 0;
}
/* Set up the speculative fast path for the next interrupt. */
if (drive.sel)
gpio_out_setreset &= ~4; /* gpio_out->bsrr */
else
gpio_out_setreset |= 4; /* gpio_out->brr */
}
/* Update the SELA handler. Used for switching in the Amiga HD-ID "magic".
* Must be called with interrupts disabled. */
static void update_SELA_irq(bool_t amiga_hd_id)
{
#define OFF 4
uint32_t handler = amiga_hd_id ? (uint32_t)Amiga_HD_ID
: (uint32_t)_IRQ_SELA_changed;
uint32_t entry = (uint32_t)IRQ_SELA_changed;
@ -264,15 +192,14 @@ static void update_SELA_irq(bool_t amiga_hd_id)
entry &= ~1;
/* Create a new tail-call instruction for the entry stub. */
opcode = handler - (entry + OFF*2 + 4);
opcode = handler - (entry + 6 + 4);
opcode = 0xe000 | (opcode >> 1);
/* If the tail-call instruction has changed, modify the entry stub. */
if (unlikely(((uint16_t *)entry)[OFF] != opcode)) {
((uint16_t *)entry)[OFF] = opcode;
if (unlikely(((uint16_t *)entry)[3] != opcode)) {
((uint16_t *)entry)[3] = opcode;
cpu_sync(); /* synchronise self-modifying code */
}
#undef OFF
}
static bool_t drive_is_writing(void)
@ -292,30 +219,29 @@ static void IRQ_STEP_changed(void)
struct drive *drv = &drive;
uint8_t idr_a, idr_b;
/* Clear STEP-changed flag. */
exti->pr = m(pin_step);
/* Latch inputs. */
idr_a = gpioa->idr;
idr_b = gpiob->idr;
/* Clear STEP-changed flag. */
(void)tim2->ccr2;
/* Bail if drive not selected. */
if (idr_a & m(pin_sel0))
return;
/* Deassert DSKCHG if a disk is inserted. */
if ((drv->outp & m(outp_dskchg)) && drv->inserted
&& (ff_cfg.chgrst == CHGRST_step))
/* DSKCHG asserts on any falling edge of STEP. We deassert on any edge. */
if ((drv->outp & m(outp_dskchg)) && (dma_rd != NULL))
drive_change_output(drv, outp_dskchg, FALSE);
/* Do we accept this STEP command? */
if ((drv->step.state & STEP_active) /* Already mid-step? */
if (!(idr_a & m(pin_step)) /* Not rising edge on STEP? */
|| (drv->step.state & STEP_active) /* Already mid-step? */
|| drive_is_writing()) /* Write in progress? */
return;
/* Latch the step direction and check bounds (0 <= cyl <= 255). */
drv->step.inward = !(idr_b & m(pin_dir));
if (drv->cyl == (drv->step.inward ? ff_cfg.max_cyl : 0))
if (drv->cyl == (drv->step.inward ? 255 : 0))
return;
/* Valid step request for this drive: start the step operation. */
@ -325,8 +251,7 @@ static void IRQ_STEP_changed(void)
drive_change_output(drv, outp_trk0, FALSE);
if (dma_rd != NULL) {
rdata_stop();
if (!ff_cfg.index_suppression
&& ff_cfg.track_change != TRKCHG_realtime) {
if (!ff_cfg.index_suppression) {
/* Opportunistically insert an INDEX pulse ahead of seek op. */
drive_change_output(drv, outp_index, TRUE);
index.fake_fired = TRUE;
@ -357,14 +282,17 @@ static void IRQ_SIDE_changed(void)
} while (stk_diff(t, stk_now()) < filter);
drv->head = hd;
if ((dma_rd != NULL) && (drv->image->nr_sides == 2))
if ((dma_rd != NULL) && (drv->nr_sides == 2))
rdata_stop();
}
static void IRQ_WGATE(void)
static void IRQ_WGATE_changed(void)
{
struct drive *drv = &drive;
/* Clear WGATE-changed flag. */
exti->pr = m(pin_wgate);
/* If WRPROT line is asserted then we ignore WGATE. */
if (drv->outp & m(outp_wrprot))
return;
@ -378,110 +306,6 @@ static void IRQ_WGATE(void)
}
}
static void IRQ_WGATE_rotary(void)
{
uint32_t rot_mask = board_rotary_exti_mask, pr = exti->pr;
/* Latch and clear PR[9:5] and PR[1]. */
exti->pr = pr & 0x03e2;
if (pr & m(pin_wgate))
IRQ_WGATE();
if (pr & rot_mask)
IRQ_rotary();
}
static void IRQ_MOTOR(struct drive *drv)
{
GPIO gpio = gotek_enhanced() ? gpioa : gpiob;
bool_t mtr_asserted = !(gpio->idr & m(pin_motor));
if (drv->amiga_pin34 && (ff_cfg.motor_delay != MOTOR_ignore)) {
IRQ_global_disable();
drive_change_pin(drv, pin_34, !mtr_asserted);
}
timer_cancel(&drv->motor.timer);
drv->motor.on = FALSE;
if (!drv->inserted) {
/* No disk inserted -- MOTOR OFF */
drive_change_output(drv, outp_rdy, FALSE);
} else if (ff_cfg.motor_delay == MOTOR_ignore) {
/* Motor signal ignored -- MOTOR ON */
drv->motor.on = TRUE;
drive_change_output(drv, outp_rdy, TRUE);
} else if (!mtr_asserted) {
/* Motor signal off -- MOTOR OFF */
drive_change_output(drv, outp_rdy, FALSE);
} else {
/* Motor signal on -- MOTOR SPINNING UP */
timer_set(&drv->motor.timer,
time_now() + time_ms(ff_cfg.motor_delay * 10));
}
}
static void IRQ_CHGRST(struct drive *drv)
{
if ((ff_cfg.chgrst == CHGRST_pa14)
&& (gpio_read_pin(gpioa, pin_chgrst) == O_TRUE)
&& drv->inserted) {
drive_change_output(drv, outp_dskchg, FALSE);
}
}
static void IRQ_MOTOR_CHGRST_rotary(void)
{
struct drive *drv = &drive;
bool_t changed = drv->motor.changed;
uint32_t rot_mask = board_rotary_exti_mask, pr = exti->pr;
drv->motor.changed = FALSE;
/* Latch and clear PR[15:10] */
exti->pr = pr & 0xfc00;
if (((pr & m(pin_motor)) && (ff_cfg.motor_delay != MOTOR_ignore))
|| changed)
IRQ_MOTOR(drv);
if ((pr & m(pin_chgrst))
|| changed)
IRQ_CHGRST(drv);
if (pr & rot_mask)
IRQ_rotary();
}
static void motor_chgrst_update_status(struct drive *drv)
{
drv->motor.changed = TRUE;
barrier();
IRQx_set_pending(MOTOR_CHGRST_IRQ);
}
uint32_t motor_chgrst_exti_mask;
void motor_chgrst_setup_exti(void)
{
uint32_t m = 0;
if (ff_cfg.motor_delay != MOTOR_ignore) {
_exti_route(gotek_enhanced()?0/*PA*/:1/*PB*/, pin_motor);
m |= m(pin_motor);
}
if (ff_cfg.chgrst == CHGRST_pa14) {
exti_route_pa(pin_chgrst);
m |= m(pin_chgrst);
}
motor_chgrst_exti_mask = m;
exti->imr |= m;
motor_chgrst_update_status(&drive);
}
/*
* Local variables:
* mode: C

Some files were not shown because too many files have changed in this diff Show more