Compare commits
11 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4925b3453a | ||
|
|
ee266ee6e2 | ||
|
|
01c0dba6ff | ||
|
|
c3bbf2e55f | ||
|
|
69ea975f5c | ||
|
|
de1fa12ad6 | ||
|
|
7118f6cf40 | ||
|
|
281b3c2f86 | ||
|
|
82f8bbda20 | ||
|
|
c6c32d09ce | ||
|
|
cb757ba8f0 |
134 changed files with 5076 additions and 15872 deletions
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
|
|
@ -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
14
.gitignore
vendored
|
|
@ -1,5 +1,15 @@
|
|||
*.[oa]
|
||||
.*.d
|
||||
*~
|
||||
*.ld
|
||||
*.elf
|
||||
*.bin
|
||||
*.hex
|
||||
*.orig
|
||||
*.rej
|
||||
/out
|
||||
/ext
|
||||
*.rld
|
||||
*.upd
|
||||
*.dfu
|
||||
/flashfloppy-*
|
||||
/index.html
|
||||
/HxC_Compat*
|
||||
|
|
|
|||
197
Makefile
197
Makefile
|
|
@ -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
75
README
|
|
@ -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.
|
||||
49
README.md
49
README.md
|
|
@ -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
|
||||
|
|
|
|||
393
RELEASE_NOTES
393
RELEASE_NOTES
|
|
@ -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
|
||||
|
|
|
|||
68
Rules.mk
68
Rules.mk
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
7
bootloader/Bootloader.ld.S
Normal file
7
bootloader/Bootloader.ld.S
Normal 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
28
bootloader/Makefile
Normal 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)\""
|
||||
6
bootloader/display/Makefile
Normal file
6
bootloader/display/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
RPATH = ../../src/display
|
||||
|
||||
OBJS += display.o
|
||||
OBJS += lcd.o
|
||||
OBJS += oled_font_6x13.o
|
||||
OBJS += led_7seg.o
|
||||
4
bootloader/fatfs/Makefile
Normal file
4
bootloader/fatfs/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
RPATH = ../../src/fatfs
|
||||
|
||||
OBJS += ff.o
|
||||
OBJS += ffunicode.o
|
||||
3
bootloader/gotek/Makefile
Normal file
3
bootloader/gotek/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
RPATH = ../../src/gotek
|
||||
|
||||
OBJS += board.o
|
||||
8
bootloader/usb/Makefile
Normal file
8
bootloader/usb/Makefile
Normal 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
|
||||
14
bootloader/usb/stm32_usbh_msc/Makefile
Normal file
14
bootloader/usb/stm32_usbh_msc/Makefile
Normal 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
|
||||
133
examples/FF.CFG
133
examples/FF.CFG
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
172
examples/IMG.CFG
172
examples/IMG.CFG
|
|
@ -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)
|
||||
44
inc/cache.h
44
inc/cache.h
|
|
@ -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:
|
||||
*/
|
||||
78
inc/config.h
78
inc/config.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
4
inc/da.h
4
inc/da.h
|
|
@ -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];
|
||||
|
|
|
|||
18
inc/decls.h
18
inc/decls.h
|
|
@ -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"
|
||||
|
|
|
|||
125
inc/floppy.h
125
inc/floppy.h
|
|
@ -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:
|
||||
|
|
|
|||
2
inc/fs.h
2
inc/fs.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
57
inc/list.h
57
inc/list.h
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -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:
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
56
inc/types.h
56
inc/types.h
|
|
@ -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:
|
||||
*/
|
||||
122
inc/util.h
122
inc/util.h
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
28
reloader/Makefile
Normal 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
1
reloader/Reloader.ld.S
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "../src/FlashFloppy.ld.S"
|
||||
6
reloader/display/Makefile
Normal file
6
reloader/display/Makefile
Normal 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
4
reloader/fatfs/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
RPATH = ../../src/fatfs
|
||||
|
||||
OBJS += ff.o
|
||||
OBJS += ffunicode.o
|
||||
3
reloader/gotek/Makefile
Normal file
3
reloader/gotek/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
RPATH = ../../src/gotek
|
||||
|
||||
OBJS += board.o
|
||||
8
reloader/usb/Makefile
Normal file
8
reloader/usb/Makefile
Normal 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
|
||||
14
reloader/usb/stm32_usbh_msc/Makefile
Normal file
14
reloader/usb/stm32_usbh_msc/Makefile
Normal 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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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:
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
1
src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/ff_cfg_defaults.h
|
||||
7
src/FlashFloppy.ld.S
Normal file
7
src/FlashFloppy.ld.S
Normal 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"
|
||||
43
src/Makefile
43
src/Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
176
src/bl_update.c
176
src/bl_update.c
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -8,8 +8,6 @@
|
|||
*/
|
||||
|
||||
const char fw_ver[] = FW_VER;
|
||||
const char build_date[] = __DATE__;
|
||||
const char build_time[] = __TIME__;
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
|
|
|||
135
src/cache.c
135
src/cache.c
|
|
@ -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, ¢->lru);
|
||||
list_init(¢->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(¢->lru);
|
||||
list_insert_head(&c->lru, ¢->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(¢->lru);
|
||||
if (!list_is_empty(¢->hash))
|
||||
list_remove(¢->hash);
|
||||
|
||||
/* Reinsert the cache entry in the correct hash chain, and head of LRU. */
|
||||
cent->id = id;
|
||||
list_insert_head(&c->lru, ¢->lru);
|
||||
list_insert_head(&c->hash[CACHE_HASH(id)], ¢->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:
|
||||
*/
|
||||
|
|
@ -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. */
|
||||
|
|
|
|||
24
src/config.c
24
src/config.c
|
|
@ -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);
|
||||
|
|
|
|||
119
src/console.c
119
src/console.c
|
|
@ -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
1
src/display/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/oled_font_*.c
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
2857
src/fatfs/ff.c
2857
src/fatfs/ff.c
File diff suppressed because it is too large
Load diff
147
src/fatfs/ff.h
147
src/fatfs/ff.h
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 ---*/
|
||||
|
|
|
|||
|
|
@ -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
38
src/fatfs/integer.h
Normal 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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
873
src/floppy.c
873
src/floppy.c
File diff suppressed because it is too large
Load diff
|
|
@ -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:
|
||||
*/
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* fpec_stm32f105.c
|
||||
* fpec.c
|
||||
*
|
||||
* STM32F10x Flash Memory Program/Erase Controller (FPEC).
|
||||
*
|
||||
|
|
@ -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:
|
||||
*/
|
||||
4
src/fs.c
4
src/fs.c
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue