@
@    Mecrisp-Stellaris - A native code Forth implementation for ARM-Cortex M microcontrollers
@    Copyright (C) 2013  Matthias Koch
@
@    This program is free software: you can redistribute it and/or modify
@    it under the terms of the GNU General Public License as published by
@    the Free Software Foundation, either version 3 of the License, or
@    (at your option) any later version.
@
@    This program is distributed in the hope that it will be useful,
@    but WITHOUT ANY WARRANTY; without even the implied warranty of
@    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@    GNU General Public License for more details.
@
@    You should have received a copy of the GNU General Public License
@    along with this program.  If not, see <http://www.gnu.org/licenses/>.
@

@ Besondere Helferlein für einen ganz schnellen Ringpuffer,
@ um Loran-C Signale empfangen zu können.

@ Helpers and a fast circular buffer to
@ catch Loran-C signals.

@ -----------------------------------------------------------------------------
@ Helpers and Tests, not used while capturing
@ -----------------------------------------------------------------------------

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "sample>address" @ ( sample# -- addr )
  @ Berechnet die passende Pufferadresse für die Messungsnummer.
  @ sample>address  Calculate buffer address for given sample number. 
  @ RAM is split into two chunks in memory map of this chip.
  @ This code is used for reading the buffer after capture.
@ -----------------------------------------------------------------------------
  lsls tos, #1
  subs r2, tos, #0x10000 @ $8000 shl 1
  ite hs
    addhs tos, r2, #0x20000000
    addlo tos,     #0x10000000
  bx lr
   
@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "sign16" @ ( n16 -- n32 )
@ -----------------------------------------------------------------------------
  sxth tos, tos
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg2h!" @ ( x 16-addr -- )
  @ Gleitender Mittelwert, 2 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldrh y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #1     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  strh y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg4h!" @ ( x 16-addr -- )
  @ Gleitender Mittelwert, 4 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldrh y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #2     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  strh y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg8h!" @ ( x 16-addr -- )
  @ Gleitender Mittelwert, 8 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldrh y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #3     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  strh y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg16h!" @ ( x 16-addr -- )
  @ Gleitender Mittelwert, 16 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldrh y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #4     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  strh y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg2!" @ ( x addr -- )
  @ Gleitender Mittelwert, 2 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  ldr  y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #1     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  str  y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg4!" @ ( x addr -- )
  @ Gleitender Mittelwert, 4 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldr y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #2     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  str y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg8!" @ ( x addr -- )
  @ Gleitender Mittelwert, 8 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  @   x belegt mit dem neuen TOS
  @   w ist der neu hinukommende Messwert
  @ tos ist die Adresse

  ldr  y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #3     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  str  y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "avg16!" @ ( x addr -- )
  @ Gleitender Mittelwert, 16 Mittelungen
@ -----------------------------------------------------------------------------
  ldm psp!, {w, x} @ X is the new TOS after the store completes.

  ldr  y, [tos]     @ Alten Inhalt laden
  lsrs z, y, #4     @ Einen Teil vom gleitenden Mittelwert abziehen
  subs y, z
  adds y, w         @ Neuigkeiten hinzuaddieren
  str  y, [tos]     @ Zurückschreiben

  mov tos, x
  bx lr

@ -----------------------------------------------------------------------------
@ Code running for capturing signals
@ -----------------------------------------------------------------------------

.equ adc1_base, 0x40012000
.equ adc1_cr2,  adc1_base + 0x08 @ ADC Conversion Start register
.equ adc1_dr,   adc1_base + 0x4C @ ADC Data Register


@ .equ DAC_Base,    0x40007400
@ .equ DAC_DHR12R1, DAC_Base + 0x08
@ .equ DAC_DHR12R2, DAC_Base + 0x14

@ .equ PORTB_Base,  0x40020400
@ .equ PORTB_ODR,   PORTB_Base + 0x14

r_samples   .req r8
r_sampleno  .req r9

r_offset    .req r10
r_tack      .req r11 @ Schaltzyklenzähler

r_gri       .req r12 @ Exchanged r8 / r12 because of interrupt entry pushing

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "gri@" @ ( -- r_samples )
@ -----------------------------------------------------------------------------
   pushda r_gri
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "gri!" @ ( r_samples -- )
@ -----------------------------------------------------------------------------
   popda r_gri
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "sampleno@" @ ( -- r_samples )
@ -----------------------------------------------------------------------------
   pushda r_sampleno
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "sampleno!" @ ( r_samples -- )
@ -----------------------------------------------------------------------------
   popda r_sampleno
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "samples@" @ ( -- r_samples )
@ -----------------------------------------------------------------------------
   pushda r_samples
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "samples!" @ ( r_samples -- )
@ -----------------------------------------------------------------------------
   popda r_samples
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "offset@" @ ( -- r_samples )
@ -----------------------------------------------------------------------------
   pushda r_offset
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "offset!" @ ( r_samples -- )
@ -----------------------------------------------------------------------------
   popda r_offset
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "tack@" @ ( -- r_tack )
@ -----------------------------------------------------------------------------
   pushda r_tack
   bx lr

@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "tack!" @ ( r_tack -- )
@ -----------------------------------------------------------------------------
   popda r_tack
   bx lr


@ -----------------------------------------------------------------------------
  Wortbirne Flag_visible, "loran-register-init" @ ( -- )
  @ Bereitet die Register für die Aufnahme vor.
  @ Prepares registers for capture.
@ -----------------------------------------------------------------------------
  
  ldr  r_gri, =#74990 @ GRI schonmal sinnvoll setzen
  movs r_sampleno, #0 @ Am Anfang des Puffers
  movs r_offset, #0 @ Am Anfang keinen Offset
  movs r_samples, #0 @ Am Anfang keine Aufnahmen.  
  movs r_tack, #200 @ Am Anfang noch keine Tick/Tack-Zyklen, Tackperiode auf 200

  bx lr


.equ led_orange, 0x2000


@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "exact-crystal-loran-handler" @ ( -- )
  @ Erledigt den gesamten Loran-C Analog-Digital-Wandler Interrupt.
  @ ADC interrupt handler - Complete capture logic inside
@ -----------------------------------------------------------------------------
exact_crystal_loran_handler:
  @ Register 0=w, 1=x, 2=y, 3=z, 12 saved by interrupt entry sequence.
  @ Registers 8-12 not used in Mecrisp, they are available as "global variables".

  @ Orange an:
  movw r3, #0x0C18  @ portd_bsrr 0x40020C18
  movt r3, #0x4002
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3]

  @ AD-Wandler bearbeiten
  @ r1 already contains 0x2000 :-) @ movw r1, #0x2000   @ .equ adc1_base, 0x4001204C
  movt r1, #0x4001
  ldr r0, [r1, 0x4C] @ Fetch sample

    movs r2, #0x0001   @ Restart ADC immediately !
    movt r2, #0x4000   @  ADON SWSTART or ADC1_CR2 !  Start next conversion   1<<30 | 1 = 0x40000001
    str r2, [r1, 0x08]

  @ r0 muss nun erhalten bleiben, darin ist der Messwert !

  @ Clear Timer Interrupt Flags: 0 TIM2_SR !   Alle Interrupt-Flags löschen
  movs r1, #0x40000000  @ tim2_sr @ 0x40000010
  movs r2, #0
  str  r2, [r1, 0x10]

  @ Alle Hardwarezugriffe sind nun abgeschlossen. Habe Zeit und Ruhe, die Messwerte zu speichern !

  cmp r_samples, #0  @ Wie viele Samples sollen noch aufgenommen werden ?
  beq 1f             @ Ansonsten nicht aufnehmen.

    subs r_samples, #1 @ Ein Sample weniger
    subs r0, r_offset  @ Subtract Offset for wider range

    @ sample>address  Calculate buffer address for current sample. 
    @ RAM is split into two chunks in memory map of this chip.

    lsls r1, r_sampleno, #1
    subs r2, r1, #0x10000 @ $8000 shl 1
    ite hs
      addhs r1, r2, #0x20000000
      addlo r1,     #0x10000000

    @ Store average, r0: Measurement, r1: Place to store.
    ldrh r2, [r1]
    adds r2, r0   @ Einfach aufaddieren.
    strh r2, [r1]

1: @ Increment circular sample pointer

  adds r_sampleno, #1     @ Increment sample pointer  Ringpufferzeiger vorrücken
  cmp r_sampleno, r_gri   @ Reached GRI ?             Hat er den Endwert erreicht oder überschritten ?

  it hs
    movhs r_sampleno, #0  @ Back to zero ! Zurück auf Null !
                          @ Counts from 0 to gri-1 in r_sampleno


  @ Orange aus:
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3, #2]    @ Reset a bit in portd_bsrr+2

  bx lr


@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "slow-crystal-loran-handler" @ ( -- )
  @ Erledigt den gesamten Loran-C Analog-Digital-Wandler Interrupt.
  @ ADC interrupt handler - Complete capture logic inside
@ -----------------------------------------------------------------------------
slow_crystal_loran_handler:
  @ Register 0=w, 1=x, 2=y, 3=z, 12 saved by interrupt entry sequence.
  @ Registers 8-12 not used in Mecrisp, they are available as "global variables".

  @ Orange an:
  movw r3, #0x0C18  @ portd_bsrr 0x40020C18
  movt r3, #0x4002
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3]

  @ AD-Wandler bearbeiten
  @ r1 already contains 0x2000 :-) @ movw r1, #0x2000   @ .equ adc1_base, 0x4001204C
  movt r1, #0x4001
  ldr r0, [r1, 0x4C] @ Fetch sample

    movs r2, #0x0001   @ Restart ADC immediately !
    movt r2, #0x4000   @  ADON SWSTART or ADC1_CR2 !  Start next conversion   1<<30 | 1 = 0x40000001
    str r2, [r1, 0x08]

  @ r0 muss nun erhalten bleiben, darin ist der Messwert !

  @ Clear Timer Interrupt Flags: 0 TIM2_SR !   Alle Interrupt-Flags löschen
  movs r1, #0x40000000  @ tim2_sr @ 0x40000010
  movs r2, #0
  str  r2, [r1, 0x10]

  @ Tack erhöhen
  adds r_tack, #0x10000 @ High-Teil ist der Zähler

  @ Vergleiche Tackperiode mit dem jetzigen Tack
  cmp r_tack, r_tack, lsl #16

  @ Aktion je nach Wert:
  itte hs
    movshs r2, #58        @ Einen Takt weniger zum Aufholen
    uxthhs r_tack, r_tack @ Zählung beginnt von vorne, High-Teil ausnullen.
    movslo r2, #59        @ Normal für 1 MHz.

  str  r2, [r1, 0x2C]     @ ldr r2, =tim2_arr @ Timer-Nachladewert setzen @ $4000002C


  @ Alle Hardwarezugriffe sind nun abgeschlossen. Habe Zeit und Ruhe, die Messwerte zu speichern !

  cmp r_samples, #0  @ Wie viele Samples sollen noch aufgenommen werden ?
  beq 1f             @ Ansonsten nicht aufnehmen.

    subs r_samples, #1 @ Ein Sample weniger
    subs r0, r_offset  @ Subtract Offset for wider range

    @ sample>address  Calculate buffer address for current sample. 
    @ RAM is split into two chunks in memory map of this chip.

    lsls r1, r_sampleno, #1
    subs r2, r1, #0x10000 @ $8000 shl 1
    ite hs
      addhs r1, r2, #0x20000000
      addlo r1,     #0x10000000

    @ Store average, r0: Measurement, r1: Place to store.
    ldrh r2, [r1]
    adds r2, r0   @ Einfach aufaddieren.
    strh r2, [r1]

1: @ Increment circular sample pointer

  adds r_sampleno, #1     @ Increment sample pointer  Ringpufferzeiger vorrücken
  cmp r_sampleno, r_gri   @ Reached GRI ?             Hat er den Endwert erreicht oder überschritten ?

  it hs
    movhs r_sampleno, #0  @ Back to zero ! Zurück auf Null !
                          @ Counts from 0 to gri-1 in r_sampleno


  @ Orange aus:
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3, #2]    @ Reset a bit in portd_bsrr+2

  bx lr


@ -----------------------------------------------------------------------------
  Wortbirne Flag_inline, "fast-crystal-loran-handler" @ ( -- )
  @ Erledigt den gesamten Loran-C Analog-Digital-Wandler Interrupt.
  @ ADC interrupt handler - Complete capture logic inside
@ -----------------------------------------------------------------------------
fast_crystal_loran_handler:
  @ Register 0=w, 1=x, 2=y, 3=z, 12 saved by interrupt entry sequence.
  @ Registers 8-12 not used in Mecrisp, they are available as "global variables".

  @ Orange an:
  movw r3, #0x0C18  @ portd_bsrr 0x40020C18
  movt r3, #0x4002
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3]

  @ AD-Wandler bearbeiten
  @ r1 already contains 0x2000 :-) @ movw r1, #0x2000   @ .equ adc1_base, 0x4001204C
  movt r1, #0x4001
  ldr r0, [r1, 0x4C] @ Fetch sample

    movs r2, #0x0001   @ Restart ADC immediately !
    movt r2, #0x4000   @  ADON SWSTART or ADC1_CR2 !  Start next conversion   1<<30 | 1 = 0x40000001
    str r2, [r1, 0x08]

  @ r0 muss nun erhalten bleiben, darin ist der Messwert !

  @ Clear Timer Interrupt Flags: 0 TIM2_SR !   Alle Interrupt-Flags löschen
  movs r1, #0x40000000  @ tim2_sr @ 0x40000010
  movs r2, #0
  str  r2, [r1, 0x10]

  @ Tack erhöhen
  adds r_tack, #0x10000 @ High-Teil ist der Zähler

  @ Vergleiche Tackperiode mit dem jetzigen Tack
  cmp r_tack, r_tack, lsl #16

  @ Aktion je nach Wert:
  itte hs
    movshs r2, #60        @ Ein Extratakt zum Bremsen
    uxthhs r_tack, r_tack @ Zählung beginnt von vorne, High-Teil ausnullen.
    movslo r2, #59        @ Normal für 1 MHz.

  str  r2, [r1, 0x2C]     @ ldr r2, =tim2_arr @ Timer-Nachladewert setzen @ $4000002C


  @ Alle Hardwarezugriffe sind nun abgeschlossen. Habe Zeit und Ruhe, die Messwerte zu speichern !

  cmp r_samples, #0  @ Wie viele Samples sollen noch aufgenommen werden ?
  beq 1f             @ Ansonsten nicht aufnehmen.

    subs r_samples, #1 @ Ein Sample weniger
    subs r0, r_offset  @ Subtract Offset for wider range

    @ sample>address  Calculate buffer address for current sample. 
    @ RAM is split into two chunks in memory map of this chip.

    lsls r1, r_sampleno, #1
    subs r2, r1, #0x10000 @ $8000 shl 1
    ite hs
      addhs r1, r2, #0x20000000
      addlo r1,     #0x10000000

    @ Store average, r0: Measurement, r1: Place to store.
    ldrh r2, [r1]
    adds r2, r0   @ Einfach aufaddieren.
    strh r2, [r1]

1: @ Increment circular sample pointer

  adds r_sampleno, #1     @ Increment sample pointer  Ringpufferzeiger vorrücken
  cmp r_sampleno, r_gri   @ Reached GRI ?             Hat er den Endwert erreicht oder überschritten ?

  it hs
    movhs r_sampleno, #0  @ Back to zero ! Zurück auf Null !
                          @ Counts from 0 to gri-1 in r_sampleno


  @ Orange aus:
  movs r1, #0x2000 @ .equ led_orange, 0x2000
  strh r1, [r3, #2]    @ Reset a bit in portd_bsrr+2

  bx lr





loran_handler_ende:

@ Puffer löchen:         gri @ 0 do i sample>address 0 h! loop
@ Aufnahme starten mit:  74990 16 * debug! 
@ Abwarten:              begin debug@ 0= until 
@ Routine bleibt in Synchronisation zum Signal.


  @ Tick-Tack-Logik für die Frequenzstabilisierung: 
  @ zähler @ tackperiode @ u>= if 0 zähler ! 70 tim2_arr ! else 60 tim2_arr ! then \ Timer läuft mit 30 MHz (?) 

  @ Zähler | Tackperiode

  @      0 | 0216           0000 0216 < 0216 0000 
  @      1 | 0216           0001 0216 < 0216 0000
  @      2 | 0216           0002 0216 < 0216 0000

  @    215 | 0216           0215 0216 < 0216 0000
  @    216 | 0216           0216 0216 > 0216 0000
  @  ..217 | 0216           0217 0216 > 0216 0000

  @ Gedanke: r_tack enthält beides ! Sowohl den Zähler als auch die Tackperiode.
  @ Muss hier addieren und vergleichen...
