Compare commits
2 commits
55f5008540
...
4920c5b8e1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4920c5b8e1 | ||
|
|
9723c5b3d6 |
2 changed files with 109 additions and 174 deletions
245
src/README.md
245
src/README.md
|
|
@ -1,194 +1,129 @@
|
||||||
# Turbo Weather
|
# THHOR Cosmic Ray Sensor
|
||||||
|
|
||||||
## ATtiny424SS resources
|
## ATtiny3224 resources
|
||||||
|
|
||||||
- `TCA0-WO0-PB0`: generate the 32768kHz clock for the MS5534C
|
- `TCA0`: ADC trigger clock
|
||||||
- `SPI0-PA1…3`: communication with the MS5534C
|
- `SPI0-PA1…3, 7`: communication with flash and FPGA
|
||||||
- `USART0-RxD/TxD-PB2…3`: transmission of data, receive commands
|
- `USART0-RxD/TxD-PB0,2…3`: transmission of data, receive commands
|
||||||
- `PORTB-PB1`: enable the RF power regulator
|
- `PORTB-PB1`: enable the RF power regulator
|
||||||
- `PORTA-PA5`: light up the LED
|
- `ADC`: internal sources.
|
||||||
- `ADC0-PA4,6,7`: read Batterie, NTC, and RF power voltage, and internal sources.
|
|
||||||
- `PIT`: generate clock tick, to wake the µC once per second from deep sleep.
|
- `PIT`: generate clock tick, to wake the µC once per second from deep sleep.
|
||||||
|
- `RTC`: clock
|
||||||
- `USERROW`: store persistent configuration
|
- `USERROW`: store persistent configuration
|
||||||
- `EEPROM`: store `ADC` readings configuration, store sensor test data records.
|
- `EEPROM`: io configuration, `ADC` readings configuration
|
||||||
- `RAM`: 256 byte TX buffer, 16 bytes RX buffer, ~128 bytes stack.
|
- `RAM`: 64 byte TX buffer, 16 bytes RX buffer, ~128 bytes stack.
|
||||||
- `FLASH`: pretty full. With lots of assembly, -O2 fits with -DDEBUG.
|
|
||||||
|
|
||||||
## Source files
|
## Source files
|
||||||
|
|
||||||
- `bate.c`: main program, interface to the MS5534C
|
- `thhor.c`: main program, interface to the MS5534C.
|
||||||
- `calib.c`: calculate the calibrated the pressure sensor readings.
|
- `config.c`: io configuration, userrow config.
|
||||||
- `adc.c`: configure and run the ADC, calculate calibrated results
|
- `adc.c`: configure and run the ADC, calculate calibrated results
|
||||||
- `mul.c`: handcraft 16-bit multiplication and decimal printing.
|
|
||||||
- `rtc.c`: configure the _periodic interrupt timer_ `PIT`.
|
- `rtc.c`: configure the _periodic interrupt timer_ `PIT`.
|
||||||
- `spi.c`: configure the `SPI0` and run a 16-bit frame.
|
- `spi.c`: configure the `SPI0` and run a 16-bit frame.
|
||||||
- `uart.c`: configure the USART0, provide Tx and Rx buffers for IO.
|
- `uart.c`: configure the USART0, provide Tx and Rx buffers for IO.
|
||||||
|
- `uart_tx.S`: assembly implemention for uart.
|
||||||
|
- `base85.c`: Base85 encode/decode 16-bytes `cmd_buffer` on UART.
|
||||||
|
- `base85a.S` assembly implemention for bch4369.
|
||||||
- `cmd.c`: parse and run simple commands received from the UART.
|
- `cmd.c`: parse and run simple commands received from the UART.
|
||||||
|
- `flash.c`: talk to the external flash via SPI
|
||||||
|
- `bch4369.c`: EDAC on flash pages
|
||||||
|
- `flga.c`: talk to the FPGA via SPI
|
||||||
|
- `pipe.c`: move data streams
|
||||||
|
|
||||||
## Output records
|
## UART protocol
|
||||||
|
|
||||||
The programm issues several types of output lines. Each type is
|
The host sends commands consisting of
|
||||||
prefixed with a unique capital letter.
|
- a capital letter,
|
||||||
|
- flags
|
||||||
|
- optionally one space and 16 base85 encoded `data` bytes
|
||||||
|
- a newline
|
||||||
|
|
||||||
- `V`: sent at boot, a greeting and version.
|
When the first flags is a digit `0`…`4`, it selects a section of the
|
||||||
- `B`: sent at boot, a single byte `RSTCTRL.RSTFR`, the reset reason.
|
block buffer. When no section is selected, the command operates on
|
||||||
- `S`: config record (`SEND_CONFIG`): hex dump of the `SIGROW`.
|
the `data` buffer directly, where applicable.
|
||||||
- `F`: config record (`SEND_CONFIG`): hex dump of the `FUSES`.
|
|
||||||
- `U`: config record (`SEND_CONFIG`): hex dump of the `USERROW`.
|
|
||||||
- `C`: config record (`SEND_CONFIG`): hex dump of the `config` structure in `RAM`.
|
|
||||||
- `E`: config record (`SEND_CONFIG`): hex dump of the ADC configuration in `EEPROM`.
|
|
||||||
- `W`: calibration record (`SEND_BATEW`): sensor calibration data (hex) read from the sensor.
|
|
||||||
- `D`: sensor record (`SEND_BATED`): sensor reading data (hex) acquired from the sensor.
|
|
||||||
- `P`: pressure record (`SEND_CALIB`): sensor readings in natural units.
|
|
||||||
- `A`: ADC readings (`SEND_ADC_HEX`): hex words, 16-bit range.
|
|
||||||
- `V`: ADC readings (`SEND_ADC_VOLT`): calibrated, natural units.
|
|
||||||
- `X`: Debug (`SEND_DEBUG`): hex dump of the `debug_data` structure.
|
|
||||||
- `R`: command reception.
|
|
||||||
|
|
||||||
Config records are sent at boot, with test data, and when enabled via
|
When the last flag is a haf-mesh `=` and there is no `data`, and the
|
||||||
`SEND_CONFIG` with a subset of sensor readings. The config byte `confp`
|
previous command was the same letter, then the `data` of the previous
|
||||||
is the number of readings sent in between without sending config records.
|
command is used again, possibly modified by the previous command
|
||||||
|
execution.
|
||||||
|
|
||||||
Debug data is only available when not disabled during compilation. Do
|
The µC answers with
|
||||||
`make DEBUG=-DNODEBUG` to disable all debugging code and data.
|
- a mesh `#`,
|
||||||
|
- the command letter and used flags,
|
||||||
|
- optionally one space and 16 base85 encoded `data` bytes,
|
||||||
|
- a newline.
|
||||||
|
|
||||||
The `SEND` flags are stored in byte[3] of the `config` structure to
|
In case of any error the answer is terminated with a what `?` and a newline,
|
||||||
enable the respective output records, with the bit positions
|
without encoded data bytes.
|
||||||
|
|
||||||
- `SEND_CONFIG = 0x01`
|
### Commands
|
||||||
- `SEND_BATED = 0x02`
|
|
||||||
- `SEND_BATEW = 0x04`
|
|
||||||
- `SEND_CLOCK = 0x08`
|
|
||||||
- `SEND_CALIB = 0x10`
|
|
||||||
- `SEND_ADC_HEX = 0x20`
|
|
||||||
- `SEND_ADC_VOLT = 0x40`
|
|
||||||
- `SEND_DEBUG = 0x80`
|
|
||||||
|
|
||||||
## Configuration
|
- `A`: ADC
|
||||||
|
All variants return number of completed channels.
|
||||||
|
There are two configued channels, T and Vcc.
|
||||||
|
* `A`: return status
|
||||||
|
* `A!`: start conversions
|
||||||
|
* `A<`: return ADC readings
|
||||||
|
|
||||||
At boot, the configuration is copied from the `USERROW` to the
|
- `B`: Block buffer ops, return valid sections.
|
||||||
`config` structure in `RAM`, if the first byte in the `USERROW` is
|
The block buffer is 80 bytes, in five sections.
|
||||||
the magic `0xba`, and the second byte matches the version of the
|
One flash page is 8 blocks of 64 bytes, plus one section 4 for EDAC in the last block.
|
||||||
`config` structure, currently `0x08`. Else, the defaults are used.
|
When no section is selected, the `data` is used in the cmd buffer.
|
||||||
|
* `B0`…`B4`: select section.
|
||||||
|
* `B@`: mark all sections invalid.
|
||||||
|
* `B0 data`: fill the invalid selected section with the data and mark is valid..
|
||||||
|
* `B0! data`: fill the selected section with the data even is it is valid.
|
||||||
|
* `B…%@`: reset the BCH4369 parity.
|
||||||
|
* `B…%`: add the selected section/data to the parity.
|
||||||
|
* `B…%!`: Complete the parity and copy to section 4 in the block buffer.
|
||||||
|
* `B…<`: Return valid data from the selected section and mark it invalid.
|
||||||
|
* `B…<!`: Return data from the selected section, evcen when invalid, and do not mark is invalid.
|
||||||
|
|
||||||
The config structure is
|
The operations _write_, _parity_, and _read_ can be combined in
|
||||||
- `[0]`: `magic = 0xba`.
|
that order, as indicated by `…`.
|
||||||
- `[1]`: `version = 0x08`.
|
|
||||||
- `[2]`: `triggers`: trigger enables.
|
|
||||||
- `[3]`: `send`: output data configuration.
|
|
||||||
- `[4]`: `power`: power management.
|
|
||||||
- `[5]`: `calib_test`: number of test records to send after a reset.
|
|
||||||
- `[6]`: `spi_div`: `SPI0.CTRLA.SPI_PRESC` \[÷64\]
|
|
||||||
- `[7]`: `mclk_delay`: number of `MCLK` ticks to wait before a reading.
|
|
||||||
- `[8]`: `period`: number of seconds-1 between readings.
|
|
||||||
- `[9]`: `confp`: number of readings without config records.
|
|
||||||
- `[10]`: `cpu_clk`: `CLKCTRL.MCLKCTRLB` \[÷2\]
|
|
||||||
- `[11]`: `mclk_period`: `TCA0.SINGLE.CMP0` \[÷76\]
|
|
||||||
- `[12]`: `baud_div`: two bytes little endian \[÷16667\]
|
|
||||||
- `[14]`: `uart_mode`: `USART0.CTRLB`
|
|
||||||
- `[15]`: `pit_period`: `RTC.CLKSEL` \[÷1024\]
|
|
||||||
- `[16]`: `immediate`: number of immediate readings at boot.
|
|
||||||
|
|
||||||
### Triggers
|
- 'C': FPGA command
|
||||||
|
* `C@`: reset the FPGA to unconfigured state.
|
||||||
|
* `C data`: send a command to the FPGA, up to 14 bytes that came back.
|
||||||
|
The command format is defined by `struct fpga_cmd`
|
||||||
|
|
||||||
The `triggers` byte\[2\] enables various reasons to do a sensor reading.
|
- `D`: Find the first free page in the flash telemetry area.
|
||||||
|
|
||||||
- `TRIGGER_ONCE = 0x01`: one reading at boot.
|
- `F`: Command to the flash chip via SPI.
|
||||||
- `TRIGGER_CONT = 0x02`: continuously read the sensor.
|
* `F': return SPI status.
|
||||||
- `TRIGGER_UART = 0x04`: read the sensor when the UART Rx input toggles.
|
* `F data`: submit command
|
||||||
- `TRIGGER_CLOCK = 0x08`: read periodically, every `period`+1 _seconds_.
|
* `F!`: Poll SPI.
|
||||||
- `TRIGGER_BREAK = 0x10`: read continuously while the UART Rx input is low.
|
* `F<`: Return the answer.
|
||||||
- `TRIGGER_IMMED = 0x20`: do any requested immediate readings.
|
|
||||||
|
|
||||||
_Seconds_ are define by the `PIT`. Those can be up to 8 real seconds
|
- `M` peek/poke.
|
||||||
long, or much shorter. _Immediate_ readings can be requested at boot
|
* `M data`: execute a peek of poke.
|
||||||
or via the command `T`.
|
* `M=`: continue the just emitted peak/poke.
|
||||||
|
|
||||||
### Power
|
`data` is a `struct peek_poke`. Up to 12 bytes can be transfered by each call.
|
||||||
|
Writing to EEPROM requires a key for the CCP.
|
||||||
|
|
||||||
The bits in the power byte\[4\] are
|
- `O`: Power/configure the FPGA, return FPGA status.
|
||||||
|
* `O0`: Turn power off.
|
||||||
|
* `O1`: Turn power on.
|
||||||
|
* `O2`: Configure from flash, if powered and unconfigured.
|
||||||
|
* `O3`: Power off if unconfigured.
|
||||||
|
* `O4`: Configure from flash, unconditionally.
|
||||||
|
|
||||||
- `POWER_DOWN = 0x01`: Enter `POWER_DOWN` sleep between readings.
|
- `P`: Pipe stream ops.
|
||||||
- `POWER_DOWN_CLI = 0x02`: Disable interrupts before `POWER_DOWN`.
|
* `P@`: Stop current stream (clear all destinations).
|
||||||
- `STOP_MCLK = 0x04`: Stop the `MCLK` after the reading.
|
* `P data`: confiure ans start a stream.
|
||||||
- `POWER_LED = 0x08`: Turn on the LED during a reading.
|
* `P.`: Poll the flash stream.
|
||||||
- `POWER_STDBY = 0x10`: Enter `STANDBY` sleep between readings.
|
* `P,`: Poll the flashj stream with ACK.
|
||||||
- `POWER_RX = 0x20`: Do not `POWER_DOWN` when the `UART` Rx is active
|
* `P!`: Poll the pipe.
|
||||||
- `POWER_RF = 0x40`: Turn on the RF transmitter power.
|
|
||||||
- `POWER_LINE = 0x80`: Send a preamble after rfen()
|
|
||||||
|
|
||||||
`POWER_STDBY` is sufficient to reduce the power to a minimum.
|
The poll options are usefull for debugging, when mainloop polling is on hold.
|
||||||
`POWER_RX` does not seem to work. From `POWER_DOWN_CLI` we shall
|
Do `poke("magic+2", 0x01, s=1)` to set the pipe polling on hold.
|
||||||
never wake up, unless the `WDT` is enabled in the fuses. When the
|
|
||||||
`MCLK` is stopped after a reading, it will be truned on and
|
|
||||||
`mclk_delay` ticks must pass before communication with the sensor
|
|
||||||
resumes. That delay is probably not necessary. `POWER_RF` is
|
|
||||||
necessary to bias the NTC measured by ADC readings. The `POWER_LINE`
|
|
||||||
preamble charges the AC-coupled output of the RF receiver to
|
|
||||||
properly receive subsequent characters.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
Commandlines received via the UART must be in the format
|
|
||||||
- `«C» {[«space»]+ «hex»}+ [«space»]+ «linefeed»`
|
|
||||||
|
|
||||||
A command letter, uppercase, and up to seven (optionally space
|
|
||||||
separated) hex bytes, optionally followed by more space characters and
|
|
||||||
a linefeed. A hex character is one or two hex digits, letters `a`…`f`
|
|
||||||
_must_ be lowercase. Obviously, a single hex digit must be separated
|
|
||||||
with space characters from any following byte. No spaces are required
|
|
||||||
at all when all bytes are written with two digits. The Rx buffer can
|
|
||||||
accomodate commandlines up to 15 bytes long, including the newline
|
|
||||||
char.
|
|
||||||
|
|
||||||
The parser echos the received line, preceeded with the string `R>`.
|
|
||||||
When the command is valid, the answer bytes are sent prefixed with
|
|
||||||
`R!`. Invalid commands are answered with `R?`.
|
|
||||||
|
|
||||||
Most commands require a specific number of hex bytes as arguments. As
|
|
||||||
currently implemented, all commands echo all their arguments and one
|
|
||||||
additional byte.
|
|
||||||
|
|
||||||
### List of commands:
|
|
||||||
|
|
||||||
- `R «ccp»`: Reboot the µC. The argument byte must be `d8`, the
|
|
||||||
`CCP[IOREG]` key, to validate the reset.
|
|
||||||
|
|
||||||
- `C «key» «bytes»…`: write to the `config` structure in `RAM`
|
|
||||||
- `U «key» «bytes»…`: write to persistent config in the `USERROW`
|
|
||||||
- `E «key» «bytes»…`: write to `EEPROM`
|
|
||||||
|
|
||||||
Up to six «bytes» are written. The «key» must be `9d`, the
|
|
||||||
`CCP[SPM]` key, for the persistent stores, and `ba` for the `RAM`.
|
|
||||||
These commands return the old value of the first byte that was
|
|
||||||
written.
|
|
||||||
|
|
||||||
- `T «n»`: trigger «n» more immediate sensor readings.
|
|
||||||
|
|
||||||
- `M «aaaa»`: reads any memory address «aaaa» (two bytes, big endian)
|
|
||||||
and prints the byte.
|
|
||||||
|
|
||||||
- `W «aaaa» «bb»`: write a byte «bb» into any address «aaaa», return
|
|
||||||
the old value of that memory location.
|
|
||||||
|
|
||||||
- `K «bb» «bb» «bb» «bb»`: set the clock. The 32-bit time value must
|
|
||||||
be sent little endian.
|
|
||||||
|
|
||||||
- `D «n»`: process and send calibrated readings for «n» test data
|
|
||||||
records. The `EEPROM` has space for up to five data records.
|
|
||||||
|
|
||||||
## Toolchain
|
## Toolchain
|
||||||
|
|
||||||
The ATtiny424 µC requires an up-to-date toolchain
|
The ATtiny3224 µC requires an up-to-date toolchain
|
||||||
- binutits: `./configure --target=avr --program-prefix=avr-`
|
- binutits: `./configure --target=avr --program-prefix=avr-`
|
||||||
- gcc: `../gcc/configure --program-prefix=avr- --with-avrlibc --target=avr --enable-languages=c --disable-nls`
|
- gcc: `../gcc/configure --program-prefix=avr- --with-avrlibc --target=avr --enable-languages=c --disable-nls`
|
||||||
- avr-libc: `./configure --host=avr`
|
- avr-libc: `./configure --host=avr`
|
||||||
|
|
||||||
## TODO (all done)
|
|
||||||
- √ Use the SPI hardware to talk to the sensor.
|
|
||||||
- √ Send results via UART hardware.
|
|
||||||
- × Setup the watchdog. √ Use PIT instead
|
|
||||||
- √ Control power to the RF transmitter
|
|
||||||
- √ Light the LED.
|
|
||||||
- √ Readout the ADCs, thermistors.
|
|
||||||
- √ Readout the internal temperature sensor.
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ extern struct io_config ee9_start[], ee9_end[];
|
||||||
|
|
||||||
#define UART_VPORT VPORTB
|
#define UART_VPORT VPORTB
|
||||||
#define UART_PORT PORTB
|
#define UART_PORT PORTB
|
||||||
#define TxE_PIN 1
|
#define TxE_PIN 0
|
||||||
#define TxD_PIN 2
|
#define TxD_PIN 2
|
||||||
#define RxD_PIN 3
|
#define RxD_PIN 3
|
||||||
#define RxD_PINCTRL UART_PORT.PIN3CTRL
|
#define RxD_PINCTRL UART_PORT.PIN3CTRL
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue