Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:55 02 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Armmite H7: V5.05.02: 1.5MHz ADC

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 06:56pm 18 Dec 2018
Copy link to clipboard 
Print this post

Quite pleased with this one.

2018-12-19_054119_Armmite1.3.zip
It implements new ADC functionality that can capture up to 3 channels of data in the background at up to 500KHz per channel with user selectable triggering - ideal for zero-crossing detection or similar.

The functionality is all driven by the new command ADC

To enable the ADCs use the command

ADC OPEN frequency, channel1-pin [,channel2-pin] [,channel3-pin] [, interrupt]


"frequency" is the sampling frequency in Hz. The maximum frequency is 500KHz.
From 320KHz to 500KHz the conversion is 8-bits per channel
From 160KHz to 320KHz the conversion is 10-bits per channel
From 80KHz to 160KHz the conversion is 12-bits per channel
From 40KHz to 80KHz the conversion is 14-bits per channel
Below 40KHz conversion is 16-bits per channel
This is automatically compensated for in the firmware.

"channel1-pin" can be one of 34, 35, 36, 37, 42, 43, 44, 45, 46, 47, 49, 50
"channel2-pin" can be one of 13, 14, 15, 18, 19, 21, 22, 26, 27, 28, 29
"channel3-pin" can be one of 53, 54

The "interrupt" parameter is a normal MMBasic subroutine that can be called when the conversion completes.

The ADC is started using the command

ADC START channel1array!() [,channel2array!()] [,channel3array!()]


The floating point arrays must be the same size and the size will determine the number of samples.

Once the start command is issued the ADC(s) will start converting the input signals into the arrays at the frequency specified.

If the OPEN command includes an interrupt then the command is non-blocking. If an interrupt is not specified the command is blocking.

The samples are returned as floating point values between 0 and VCC. VCC is assumed to be 3.3V but this can be altered using the command "OPTION VCC voltage". This option is reset on reboot.

The ADCs can be disabled with the command

ADC CLOSE


After the OPEN command has been issued the frequency can be adjusted using the command

ADC FREQUENCY frequency


This command is only allowed if the number of bits calculated in the table above does not change otherwise it will give an error.

The new firmware also supports ADC triggering using the command

ADC TRIGGER channel, level


This should be specified before the ADC START command.
The "channel" can be a number between one and three depending on the number of pins specified in the ADC OPEN command.
The level can be between -VCC and VCC.
A positive number indicates that you are looking for a positive going transition through the specified voltage.
A negative number indicates that you are looking for a negative going transition through the specified voltage (as in the example).






Option explicit
Option default none
Option VCC 3.309
Dim integer i, j
CLS
'
' First set up some signals using the onboard DAC
' connect pin 40 to pin 49 and pin 41 to pin 22
' connect a potentiometer to pin 53 to use as a trigger
'
Dim a(799) As float, b(799) As float, t(799) As float, c%(179), d%(179)
For i=0 To 179
c%(i)=Sin(Rad(i*2))*1500+2048
d%(i)=i*2000/180+2048
Next i%
DAC start 100000,c%(),d%()
'
ADC open 100000,49,22,53,adc_done
ADC trigger 3,-2.0 ' specify the potentiometer channel to use to trigger with a negative slope through 2.0V
ADC start a(), b(), t()
Do
Loop While j=0
Box 0,0,MM.HRes,MM.VRes

Pixel 0, 200-a(0)*50, RGB(magenta)
Pixel 0, 470-b(0)*50, RGB(green)

For i=1 To 799
Line i-1,200-a(i-1)*50 , i, 200-a(i)*50 , 1, RGB(magenta)
Line i-1,470-b(i-1)*50 , i, 470-b(i)*50 , 1, RGB(green)
Next i


Text MM.HRes\2,MM.VRes\2,"Pre-trigger "+Str$(t(0),1,5)+" Post-trigger "+Str$(t(1),1,5),CM,4
End

Sub adc_done
j=1
End Sub



This release also implements the latest DAC functionality out of the Armmite L4:
This allows you to create any arbitrary waveform using the H7's inbuilt DACs and is used in the example above.

The syntax is:

DAC START frequency, DAC1array%() [,DAC2array%()]



DAC1array%() and optional DAC2array%() should contain numbers in the range 0-4095 to suit the 12-bit DACs. The software automatically and separately uses the number of items in each of the arrays to drive the DACs.
The frequency is the rate at which the DACs change value. The maximum frequency is 700KHz. So in the example code above there are 180 items in the array c%() which are displayed at a frequency of 100,000 Hz giving a sinewave with a frequency of 100,000/180 = 555Hz. There are 90 items in the array d%() which are displayed at a frequency of 100,000 Hz giving a sinewave with a frequency of 100,000/90 = 1111Hz.

The output runs in the background and is stopped using the command.

DAC CLOSE

Edited by matherp 2018-12-20
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 08:29pm 18 Dec 2018
Copy link to clipboard 
Print this post

Very nice addition.

Jim
VK7JH
MMedit
 
KeepIS

Guru

Joined: 13/10/2014
Location: Australia
Posts: 1882
Posted: 11:08pm 18 Dec 2018
Copy link to clipboard 
Print this post

What Jim said, this just keeps getting better, thank you again for the brilliant programming and your time and effort.

Mike.

NANO Inverter: Full download - Only Hex Ver 8.1Ks
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 08:35am 19 Dec 2018
Copy link to clipboard 
Print this post

Here is the updated manual with the new commands

2018-12-19_183710_Armmite_H7_Manual.pdf Edited by matherp 2018-12-20
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 05:24pm 19 Dec 2018
Copy link to clipboard 
Print this post

One more tweak

2018-12-20_025148_Armmite1.3.zip

This now includes an FFT command to allow you do do frequency analyses of signals




The basic command FFT has the following syntax:

FFT signalarray!(),FFTarray!()


"signalarray" must be floating point and the size must be a power of 2 (e.g. s(1023) assuming OPTION BASE is zero)
"FFTarray" must be floating point and have dimension 2*N where N is the same as the signal array (e.g. f(1,1023) assuming OPTION BASE is zero)
The command will return the FFT as complex numbers with the real part in f(0,n) and the imaginary part in f(1,n)

The inverse command has the syntax:

FFT INVERSE FFTarray!(), signalarray!()


"FFTarray" must be floating point and have dimension 2*N where N must be a power of 2 (e.g. f(1,1023) assuming OPTION BASE is zero) with the real part in f(0,n) and the imaginary part in f(1,n)
"signalarray" must be floating point and the single dimension must be the same as the FFT array
The command will return the real part of the inverse transform in "signalarray"

Most useful is probably the magnitude command

FFT MAGNITUDE signalarray!(),magnitudearray!()


"signalarray" must be floating point and the size must be a power of 2 (e.g. s(1023) assuming OPTION BASE is zero)
"magnitudearray" must be floating point and the size must be the same as the signal array
The command will return the magnitude of the signal at various frequencies according to the formula:

frequency at array position N = N * sample_frequency / number_of_samples


so if the sample frequency is 10KHz and there are 1024 samples then the frequency associate with the magnitude at "magnitudearray(57)" = 57 * 10000 / 1024 = 557HZ as in the example above

NB only the first N/2 values are useful as values after N/2 are beyond the Nyquist frequency and contain no useful information.

The final FFT command returns the phase angle at each frequency

FFT PHASE signalarray!(),phasearray!()


"signalarray" must be floating point and the size must be a power of 2 (e.g. s(1023) assuming OPTION BASE is zero)
"phasearray" must be floating point and the size must be the same as the signal array
The command will return the phase angle of the signal at various frequencies according to the formula above.

The test code I used for the picture is:

Option explicit
Option default none
Option VCC 3.308
Const SAMPLESPERSEC = 10000
Const NSAMPLES = 1024
Const PLOTFREQ = NSAMPLES\512
Dim integer i, j, imax, imax1
Dim float a(NSAMPLES-1) , b(NSAMPLES-1), t(NSAMPLES-1)
Dim integer c%(179), d%(179)
Dim float m(NSAMPLES-1) , mmax , m1(NSAMPLES-1), mmax1
CLS
'
' First set up some signals using the onboard DAC
' connect pin 40 to pin 49 and pin 41 to pin 22
' connect a potentiometer to pin 53 to use as a trigger
'
For i=0 To 179
c%(i)=Sin(Rad(i*2))*1500+2048
d%(i)=i*2000/180+2048
Next i%
'
' start the DAC
'
DAC start 100000,c%(),d%()
'
' convert the signals
'
ADC open SAMPLESPERSEC, 49, 22, 53, adc_done
ADC trigger 3,-2.0
ADC start a(), b(), t()
Do
Loop While j=0
'
' frequency analyse the signals
'
FFT magnitude b(),m()
FFT magnitude a(),m1()

Box 144,0,MM.HRes-288,MM.VRes
'
' find the maximum magnitude of the frequencies
'
mmax=0
mmax1=0
For i=1 To NSAMPLES\2-1
If m(i)>mmax Then
mmax=m(i)
imax=i
EndIf
If m1(i)>mmax1 Then
mmax1=m1(i)
imax1=i
EndIf
Next i
Text 5,180,"Peak",,4
Text 5,200,Str$(imax1*SAMPLESPERSEC/NSAMPLES,4,0)+"Hz",,4
Text 5,380,"Peak",,4
Text 5,400,Str$(imax*SAMPLESPERSEC/NSAMPLES,3,0)+"Hz",,4
'
' plot the samples
'

For i=1 To 511
Line i+144, 130 - a(i-1)*40, i+145, 130 - a(i)*40, 1, RGB(magenta)
Line i+144, 420 - b(i-1)*50, i+145, 420 - b(i)*50, 1, RGB(green)
Next i
'
' plot the frequency analyses
'
For i=2 To 511
Line i+144,470-m((i-1)*PLOTFREQ/2)/mmax*100 ,i+146, 470 - m(i*PLOTFREQ/2)/mmax*100 , 1, RGB(yellow)
Line i+144,240-m1((i-1)*PLOTFREQ/2)/mmax1*100, i+146, 240 - m1(i*PLOTFREQ/2)/mmax1*100, 1, RGB(yellow)
Next i
'
End

Sub adc_done
j=1
End Sub

 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 07:50pm 19 Dec 2018
Copy link to clipboard 
Print this post

You don't own a big red suit and go around "Ho Ho Hoing" a lot by any chance?
I have a desire to extract the low frequency amplitudes of a gryo sygnal and this is just what I need.

It will save having to do the maths on a PC.

Jim
VK7JH
MMedit
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 10:00am 20 Dec 2018
Copy link to clipboard 
Print this post

Manual updated with FFT

2018-12-20_201216_Armmite_H7_Manual.pdf Edited by matherp 2018-12-21
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 03:02pm 20 Dec 2018
Copy link to clipboard 
Print this post

Hello forum.

EDIT: nope... definitely weirdness...

> RUN
1545317428 20-12-2018 14:50:28 20-12-2018 14:50:28 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429 20-12-2018 14:50:29 20-12-2018 14:50:29 1 1 4
1545317429
CTRL-C
>

all normal and as expected, then:

> ? now
Error: A sub/fun has the same name: NOW
> RUN
[LIBRARY] Sub FlagSet(bit As Integer)
Error: Duplicate name
>


same prog no longer runs, throwing bogus complaints of duplicate names - code below





Option Base 0

Const PE2=1,D56=1,CN9_14=1,CN11_46=1
Const PE3=2,D60=2,CN9_22=2,CN11_47=2
Const PE4=3,D57=3,CN9_16=3,CN11_48=3
Const PE5=4,D58=4,CN9_18=4,CN11_50=4
Const PE6=5,D59=5,CN9_20=5,CN11_62=5
Const PC13=7,CN11_23=7
Const PC14=8,CN11_25=8
Const PC15=9,CN11_27=9
Const PF0=10,D68=10,CN9_21=10,CN11_53=10
Const PF1=11,D69=11,CN9_19=11,CN11_51=11
Const PF2=12,D70=12,CN9_17=12,CN11_52=12
Const PF3=13,A3=13,CN9_7=13,CN12_58=13
Const PF4=14,A8=14,CN10_11=14,CN12_38=14
Const PF5=15,A4=15,CN9_9=15,CN12_36=15
Const PF6=18,CN11_9=18
Const PF7=19,D62=19,CN9_26=19,CN11_11=19
Const PF8=20,CN11_54=20
Const PF9=21,D63=21,CN9_28=21,CN11_56=21
Const PF10=22,A5=22,CN9_11=22,CN12_42=22
Const PH0=23,CN11_29=23
Const PH1=24,CN11_31=24
Const PC0=26,A1=26,CN9_3=26,CN11_38=26
Const PC1=27,CN11_36=27
Const PC2=28,A7=28,CN10_9=28,CN11_35=28
Const PC3=29,A2=29,CN9_5=29,CN11_37=29
Const PA0=34,D32=34,CN10_29=34,CN11_28=34
Const PA1=35,CN11_30=35
Const PA2=36,CN12_35=36
Const PA3=37,A0=37,CN9_1=37,CN12_37=37
Const PA4=40,D24=40,CN7_17=40,CN11_32=40
Const PA5=41,D13=41,CN7_10=41,CN12_11=41
Const PA6=42,D12=42,CN7_12=42,CN12_13=42
Const PA7=43,D11=43,CN7_14=43,CN12_15=43
Const PC4=44,CN12_34=44
Const PC5=45,CN12_6=45
Const PB0=46,D33=46,CN10_31=46,CN11_34=46
Const PB1=47,A6=47,CN10_7=47,CN12_24=47
Const PB2=48,D27=48,CN10_15=48,CN12_22=48
Const PF11=49,CN12_62=49
Const PF12=50,D8=50,CN7_20=50,CN12_59=50
Const PF13=53,D7=53,CN10_2=53,CN12_57=53
Const PF14=54,D4=54,CN10_8=54,CN12_50=54
Const PF15=55,CN12_60=55
Const PG0=56,CN11_59=56
Const PG1=57,D64=57,CN9_30=57,CN11_58=57
Const PE7=58,D41=58,CN10_20=58,CN12_44=58
Const PE8=59,D42=59,CN10_18=59,CN12_40=59
Const PE9=60,D6=60,CN10_4=60,CN12_52=60
Const PE10=63,D40=63,CN10_24=63,CN12_47=63
Const PE11=64,D5=64,CN10_6=64,CN12_56=64
Const PE12=65,D39=65,CN10_26=65,CN12_49=65
Const PE13=66,D3=66,CN10_12=66,CN12_55=66
Const PE14=67,D38=67,CN10_28=67,CN12_51=67
Const PE15=68,CN12_53=68
Const PB10=69,D36=69,CN10_32=69,CN12_25=69
Const PB11=70,D35=70,CN10_34=70,CN12_18=70
Const PB12=73,D19=73,CN7_7=73,CN12_16=73
Const PB13=74,D18=74,CN7_5=74,CN12_30=74
Const PB14=75,CN12_28=75
Const PB15=76,D17=76,CN7_3=76,CN12_26=76
Const PD8=77,CN12_10=77
Const PD9=78,CN11_69=78
Const PD10=79,CN12_65=79
Const PD11=80,D30=80,CN10_23=80,CN12_45=80
Const PD12=81,D29=81,CN10_21=81,CN12_43=81
Const PD13=82,D28=82,CN10_19=82,CN12_41=82
Const PD14=85,D10=85,CN7_16=85,CN12_46=85
Const PD15=86,D9=86,CN7_18=86,CN12_48=86
Const PG2=87,D49=87,CN8_14=87,CN11_42=87
Const PG3=88,D50=88,CN8_16=88,CN11_44=88
Const PG4=89,CN12_69=89
Const PG5=90,CN12_68=90
Const PG6=91,CN12_70=91
Const PG7=92,CN12_67=92
Const PG8=93,CN12_66=93
Const PC6=96,D16=96,CN7_1=96,CN12_4=96
Const PC7=97,D21=97,CN7_11=97,CN12_19=97
Const PC8=98,D43=98,CN8_2=98,CN12_2=98
Const PC9=99,D44=99,CN8_4=99,CN12_1=99
Const PA8=100,CN12_23=100
Const PA9=101,CN12_21=101
Const PA10=102,CN12_33=102
Const PA11=103,CN12_14=103
Const PA12=104,CN12_12=104
Const PA13=105,CN11_13=105
Const PA14=109,CN11_15=109
Const PA15=110,D20=110,CN7_9=110,CN11_17=110
Const PC10=111,D45=111,CN8_6=111,CN11_1=111
Const PC11=112,D46=112,CN8_8=112,CN11_2=112
Const PC12=113,D47=113,CN8_10=113,CN11_3=113
Const PD0=114,D67=114,CN9_25=114,CN11_57=114
Const PD1=115,D66=115,CN9_27=115,CN11_55=115
Const PD2=116,D48=116,CN8_12=116,CN11_4=116
Const PD3=117,D55=117,CN9_10=117,CN11_40=117
Const PD4=118,D54=118,CN9_8=118,CN11_39=118
Const PD5=119,D53=119,CN9_6=119,CN11_41=119
Const PD6=122,D52=122,CN9_4=122,CN11_43=122
Const PD7=123,D51=123,CN9_2=123,CN11_45=123
Const PG9=124,D0=124,CN10_16=124,CN11_63=124
Const PG10=125,CN11_66=125
Const PG11=126,CN11_70=126
Const PG12=127,CN11_65=127
Const PG13=128,CN11_68=128
Const PG14=129,D1=129,CN10_14=129,CN12_61=129
Const PG15=132,CN11_64=132
Const PB3=133,D23=133,CN7_15=133,CN12_31=133
Const PB4=134,D25=134,CN7_19=134,CN12_27=134
Const PB5=135,D22=135,CN7_13=135,CN12_29=135
Const PB6=136,D26=136,CN10_13=136,CN12_17=136
Const PB7=137,CN11_21=137
Const PB8=139,D15=139,CN7_2=139,CN12_3=139
Const PB9=140,D14=140,CN7_4=140,CN12_5=140
Const PE0=141,D34=141,CN10_33=141,CN12_64=141
Const PE1=142,CN11_61=142

Dim Integer TMRctr(9),TMRini(9)
Dim Integer n,Flags

Select Case MM.DEVICE$
Case "Micromite MkII"
FlagSet(63)'62 is the pin count 1=44pin
Case "ARMmite H7"
FlagSet(61)
End Select

n=0: dir=0

do
Print unixtime(now()),humantime(unixtime(now())),now(),IsDate(date$),IsTime(time$), DoW(Now())
'If FlagTest(63)=0 then PORT(PB14,1,PB7,1,PB0,1)= 2^n
loop


Sub FlagSet(bit As Integer)
Flags=Flags Or (2^bit)
End Sub

Sub FlagRes(bit As Integer)
Flags=(Flags Or (2^bit)) Xor (2^bit)
End Sub

Function FlagTest(bit As Integer) As Integer
FlagTest=Abs(Sgn(Flags And (2^bit)))
End Function


Function ZPad$(x As integer,y As integer)
'adds y leading zeros to X
ZPad$=Right$(String$(y,"0")+Str$(x),y)
End Function

Function Split(a$,b$) As Integer' returns the number of dimensions in SP$ always starts from 1 regardless of OPTION BASE
Local INTEGER z,n,m
If b$="" Then Split=0:Exit Function ' can't split with an empty delimiter

' if SP$ doesn't exist, the ERASE will cause an error, choose which ON ERROR SKIP you need

'MM.Ver <5.04
' ON ERROR SKIP or
'MM.Ver >=5.04
On ERROR SKIP 1

Erase SP$
z=1:n=0
Do 'count instances of delimiter for DIM SP$()
z=Instr(z,a$,b$)
If z=0 Then
If n=0 Then ' no delimeters
Dim SP$(1):SP$(1)=a$:Split=1:Exit Function ' only one substring
Else
Exit Do
End If
Else
n=n+1:z=z+Len(b$)
End If
Loop
m=n+1:n=1
Dim SP$(m)
Do
z=Instr(1,a$,b$)
If z=0 Then
SP$(m)=a$:Exit Do
Else
SP$(n)=Left$(a$,z-1):a$=Mid$(a$,z+Len(b$)):n=n+1
End If
Loop
Split=m
End Function

'regexp, case sensitive
Function Match(regex$,text$) ' case sensitive
Local s,n,m,f
n=Len(regex$):m=Len(text$)
Match=0
If Mid$(regex$,1,1)="^" Then
MatchHere regex$,text$,2,1,n,m,f
Match=f
Else
For s=1 To m
MatchHere regex$,text$,1,s,n,m,f
If f Then Match=s: Exit For
Next
EndIf
End Function

Sub MatchHere(regex$,text$,r,s,n,m,f)
Local i
Do While r <= n
If Mid$(regex$,r)="$" Then f=s>m: Exit Sub
If Mid$(regex$,r,1)="[" Then
i=Instr(r+2,regex$,"]")
If i Then i=i+1 Else i=r+1
ElseIf Mid$(regex$,r,1)="\" Then
i=r+2
Else
i=r+1
EndIf
If Mid$(regex$,i,1)="*" Then
MatchStar regex$,text$,r,i,s,n,m,f
Exit Sub
EndIf
If Mid$(regex$,i,1)="?" Then
MatchOptional regex$,text$,r,i,s,n,m,f
Exit Sub
EndIf
If s>m Then f=0: Exit Sub
i=r
MatchChar regex$,text$,r,s,f
If Not f Then Exit Sub
If Mid$(regex$,r+1,1)="+" Then
MatchStar regex$,text$,i,r+1,s+1,n,m,f
Exit Sub
EndIf
r=r+1: s=s+1
Loop
f=1
End Sub

Sub MatchStar(regex$,text$,r,i,s,n,m,f)
Do
MatchHere regex$,text$,i+1,(s),n,m,f
If f or s>m Then Exit Sub
MatchChar regex$,text$,(r),s,f
If Not f Then Exit Sub
s=s+1
Loop
End Sub

Sub MatchOptional(regex$,text$,r,i,s,n,m,f)
MatchHere regex$,text$,i+1,(s),n,m,f
If f or s>m Then Exit Sub
MatchChar regex$,text$,(r),s,f
If Not f Then Exit Sub
MatchHere regex$,text$,i+1,s+1,n,m,f
End Sub

Sub MatchChar(regex$,text$,r,s,f)
Local i,j
f=Mid$(regex$,r,1)="."
If f Then Exit Sub
If Mid$(regex$,r,1)="[" Then
i=Instr(r+2,regex$,"]")
If i Then
j=Instr(r+1,regex$,Mid$(text$,s,1))
f=j>0 And j<i:r=i
Exit Sub
EndIf
ElseIf Mid$(regex$,r,1)=Chr$(92) Then
r=r+1
EndIf
f=Mid$(regex$,r,1)=Mid$(text$,s,1)
End Sub


Function Now(opt as Integer) as string
Local a$

Do ' ensure the date/time doesn't change while we are processing
a$=Date$+" "+Time$
Now=Date$+" "+Time$
Loop While a$<>Now

If opt<>0 then
Now=Mid$(a$,7,4)+Mid$(a$,3,4)+Left$(a$,2)+Mid$(a$,11)
EndIf
End Function

Function DayLight(dt$,opt as integer) As Integer
'opt = 1, return daytime start, 2, return daytime end anything else return bool of daytime now
Local Integer mn,st,fn,st0,fn0,dd,mm
dd=DatePart("dd",dt$):mm=DatePart("mm",dt$)
Do
Select Case mm
Case 1:st=490:fn=960
Case 2:st=460:fn=1010
Case 3:st=405:fn=1060
Case 4:st=335:fn=1115
Case 5:st=275:fn=1165
Case 6:st=230:fn=1210
Case 7:st=230:fn=1220
Case 8:st=265:fn=1190
Case 9:st=315:fn=1115
Case 10:st=360:fn=1060
Case 11:st=415:fn=990
Case 12:st=470:fn=955
Case 13:st=490:fn=960
End Select
If fn0<>0 Then Exit Do
fn0=fn:st0=st
mm=mm+1
Loop
st=st0-(((st0-st)/30)*dd):fn=fn0-(((fn0-fn)/30)*dd)
Select Case opt
Case 1
DayLight=st
Case 2
DayLight=fn
Case Else
mn=(DatePart("h",dt$)*60)+DatePart("m",dt$)
DayLight=(mn>=st) And (mn<fn)
End Select
End Function

Function UnixTime(HHT$,opt) As integer
' seconds since 01-01-1970. no checks on the argument format
' HT$ is DD-MM-YYYY HH:MM:SS or if opt=1 HT$ is YYYY-MM-DD HH:MM:SS
' Now() returns a suitable string
Local integer n,s,y,m
Local String DD$,TT$,HT$
HT$=HHT$' preserves the original argument
m=Split(HT$," ")
If m<>2 Then UnixTime=-1:Exit Function
DD$=SP$(1):TT$=SP$(2)
m=Split(DD$,"-")
If m<>3 Then UnixTime=-1:Exit Function
If opt=0 Then
y=Val(SP$(3))
Else
y=Val(SP$(1))
EndIf
s=0
For n=1970 To y-1
s=s+365+IsLeapYear(n)
Next
For n=1 To Val(SP$(2))-1
Select Case n
Case 1,3,5,7,8,10
s=s+31
Case 2
s=s+28+IsLeapYear(y)
Case 4,6,9,11
s=s+30
End Select
Next
If opt=0 Then
s=86400*(s+Val(SP$(1))-1)
Else
s=86400*(s+Val(SP$(3))-1)
EndIf
m=Split(TT$,":")
If m<>3 Then UnixTime=-1:Exit Function
s=s+(3600*Val(SP$(1))) + (60*Val(SP$(2))) + Val(SP$(3))
UnixTime=s
End Function

Function IsLeapYear(n As integer) As integer
IsLeapYear=((n Mod 4=0) And (n Mod 100 <>0)) Or (n Mod 400=0)
End Function

Function HumanTime(UUT As Integer,opt As Integer) As String
' take seconds since 1970-01-01 (unixtime) and converts to a human form date/time as
' if opt=0 (or not specified) the format is dd-mm-yyyy hh:mm:ss to match the format of DATE$
' if opt<>0 the date part is returned as yyyy-mm-dd
Local integer d,m,s,y,z,UT
UT=UUT' preserves the original argument
If UT<0 Then HumanTime$="":Exit Function
y=1970:d=UT\86400:s=UT Mod 86400
Do
z=365+IsLeapYear(y)
If d>=z Then
d=d-z:y=y+1
Else
Exit Do
EndIf
Loop
'here, Y is the current year and d the remaining days
m=1' start at january
' days between the start of the year and the current month
Do
z=0
Select Case m
Case 1,3,5,7,8,10
If d>=31 Then d=d-31:z=1
Case 2
If IsLeapYear(y)Then
If d>=29 Then d=d-29:z=1
Else
If d>=28 Then d=d-28:z=1
EndIf
Case 4,6,9,11
If d>=30 Then d=d-30:z=1
End Select
If z=1 Then
m=m+1
Else
d=d+1:Exit Do 'first day is 1 not 0
EndIf
Loop
If opt<>0 Then
HumanTime$=Str$(y)+"-"+ZPad$(m,2)+"-"+ZPad$(d,2)
Else
HumanTime$=ZPad$(d,2)+"-"+ZPad$(m,2)+"-"+Str$(y)
EndIf
y=s\3600:s=s-y*3600
m=s\60:s=s-m*60
HumanTime$=HumanTime$+" "+ZPad$(y,2)+":"+ZPad$(m,2)+":"+ZPad$(s,2)
End Function

Function DoW(d$) As Integer '0=Sun
DoW=(4+DateDiff("dd","01-01-1970 00:00:00",d$)) mod 7
End Function

Function DateAdd(Num As Integer,Interval As String,dt As String) As String
'return a string of the datetime with the relevant period added
'add -ve to subtract e.g.
'DateAdd (2,"mm",Now()) returns the datetime time two months from now.
'DateAdd(-1000,"dd",Now()) returns the datetime a thousand days ago
Local Integer x,y,z
Select Case LCase$(Interval)
Case "s"' Seconds
DateAdd=HumanTime(UnixTime(dt)+Num)
Case "m"' Minutes
DateAdd=HumanTime(UnixTime(dt)+(Num*60))
Case "h"' Hours
DateAdd=HumanTime(UnixTime(dt)+(Num*3600))
Case "dd" 'Days
DateAdd=HumanTime(UnixTime(dt)+(Num*86400))
Case "w" 'Weeks
DateAdd=HumanTime(UnixTime(dt)+(Num*604800))
Case "mm"' calendar Months
x=Val(Mid$(dt,4,2))-1: y=Val(Mid$(dt,7,4)): z=Val(Left$(dt,2))
x=((x+Num) Mod 12)+1: y=y+Num\12
If (x=2 And z=29) And (Not IsLeapYear(y)) Then ' bludgeon for 29/02 in non-leap year
x=3:z=1
EndIf
DateAdd=ZPad$(z,2)+"-"+ZPad$(Abs(x),2)+"-"+Zpad$(y,4)+ Right$(dt$,9)
Case "yyyy"' Years
x=Val(Left$(dt,2)): y=Val(Mid$(dt,4,2)): z=Val(Mid$(dt,7,4)):
z=z+num
If (y=2 And x=29) And (Not IsLeapYear(z)) Then ' bludgeon for 29/02 in non-leap year
y=3:x=1
EndIf
DateAdd=ZPad$(x,2)+"-"+ZPad$(Abs(y),2)+"-"+Zpad$(z,4)+ Right$(dt$,9)
Case Else
DateAdd=""
End Select
End Function

Function DateDiff(Interval As String,dt1 As String,dt2 As String) As Integer
'return the number of whole intervals between two dates
'Result is +ve when DT1<DT2
'DateDiff ("dd","01/02/2001",Now()) returns the difference in whole days since 1st Feb 2001
Local Integer n,s,t,u,v,x,y,z
Select Case LCase$(Interval)
Case "s"' Seconds
DateDiff=UnixTime(dt2)-UnixTime(dt1)
Case "m"' Minutes
DateDiff=(UnixTime(dt2)-UnixTime(dt1))\60
Case "h"' Hours
DateDiff=(UnixTime(dt2)-UnixTime(dt1))\3600
Case "dd" 'Days
DateDiff=(UnixTime(dt2)-UnixTime(dt1))\86400
Case "w" 'Weeks
DateDiff=(UnixTime(dt2)-UnixTime(dt1))\604800
Case "mm"' calendar Months
t=UnixTime(dt1):u=UnixTime(dt2):s=Sgn(u-t)
If s Then
dt1=HumanTime(Min(t,u)):dt2=HumanTime(Max(t,u))
t=Val(Left$(dt1,2)):u=Val(Mid$(dt1,4,2)):v=Val(Mid$(dt1,7,4))
x=Val(Left$(dt2,2)):y=Val(Mid$(dt2,4,2)):z=Val(Mid$(dt2,7,4))
for n=v+1 to z
DateDiff=DateDiff+12
next
DateDiff=DateDiff+(y-u)
If t>x then DateDiff=DateDiff-1
EndIf
DateDiff=DateDiff*s
Case "yyyy"' Years
t=UnixTime(dt1):u=UnixTime(dt2):s=Sgn(u-t)
If s Then
dt1=HumanTime(Min(t,u)):dt2=HumanTime(Max(t,u))
t=Val(Left$(dt1,2)):u=Val(Mid$(dt1,4,2)):v=Val(Mid$(dt1,7,4))
x=Val(Left$(dt2,2)):y=Val(Mid$(dt2,4,2)):z=Val(Mid$(dt2,7,4))
DateDiff=z-v
If u>y Then
DateDiff=DateDiff-1
ElseIf u=y Then
If t>x Then DateDiff=DateDiff-1
EndIf
EndIf
DateDiff=DateDiff*s
Case Else
DateDiff=0
End Select
End Function

Function DatePart(Interval As String,dt As String) As Integer
Select Case LCase$(Interval)
Case "s"' Seconds
DatePart=Val(Right$(dt,2))
Case "m"' Minutes
DatePart=Val(Mid$(dt,15,2))
Case "h"' Hours
DatePart=Val(Mid$(dt,12,2))
Case "dd" 'Days
DatePart=Val(Left$(dt,2))
Case "mm"' calendar Month
DatePart=Val(Mid$(dt,4,2))
Case "yyyy"' Year
DatePart=Val(Mid$(dt,7,4))
Case Else
DatePart=0
End Select
End Function

Function IsTime(t$) As Integer ' times must be hh:mm:ss
IsTime=0
If Match("^[012][0123456789]:[012345][0123456789]:[012345][0123456789]$",t$) Then
If Val(Left$(t$,2))<24 Then
If Val(Mid$(t$,4,2))<60 Then
If Val(Right$(t$,2))<60 Then
IsTime=1
EndIf
EndIf
EndIf
EndIf
End Function

Function IsDate(t$,opt As Integer) As Integer
Local Integer d,m,y
IsDate=0
If opt=0 then
If Match("^[0123][0123456789][/|-][01][0123456789][/|-][12][0123456789][0123456789][0123456789]$",t$)=0 Then Exit Function
d=Val(Left$(t$,2))
m=Val(Mid$(t$,4,2))
y=Val(Right$(t$,4))
Else
If Match("^[12][0123456789][0123456789][0123456789][/|-][01][0123456789][/|-][0123][0123456789]$",t$)=0 Then Exit Function
d=Val(Right$(t$,2))
m=Val(Mid$(t$,6,2))
y=Val(Left$(t$,4))
EndIf

Select Case m
Case 1,3,5,7,8,10,12
if d<1 or d>31 Then Exit Function
Case 4,6,9,11
if d<1 or d>30 Then Exit Function
Case 2
if d<1 or d>28+IsLeapYear(y) Then Exit Function
End Select
IsDate=1
End Function



Edited by CaptainBoing 2018-12-22
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 03:51pm 20 Dec 2018
Copy link to clipboard 
Print this post

Re-written version of the FFT algorithm now takes between 20 and 50% of previous time (data dependent). Danielson-Lanczo rather than recursive.

2018-12-21_014946_Armmite1.3.zip
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 03:59pm 20 Dec 2018
Copy link to clipboard 
Print this post

hmmm... it seems that once an error is thrown it gets locked up: ( a reset restores functionality):


> ARMmite MMBasic Version 5.05.02
Copyright 2011-2018 Geoff Graham
Copyright 2016-2018 Peter Mather

> run
1545317860 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1 4
1545317861 20-12-2018 14:57:41 20-12-2018 14:57:41 1 1
> ? now()
20-12-2018 14:57:51
all ok

> run
1545317874 20-12-2018 14:57:55 20-12-2018 14:57:55 1 1 4
1545317875 20-12-2018 14:57:55 20-12-2018 14:57:55 1 1 4
1545317875 20-12-2018 14:57:55 20-12-2018 14:57:55 1 1 4
1545317875 20-12-2018 14:57:55 20-12-2018 14:57:55 1 1 4
1545317875 20-12-2018 14:57:55 20-12-2018 14:57:55 1 1
code runs fine, now comes a deliberate error (no parenthesis)

> ? now
Error: A sub/fun has the same name: NOW
> run
[LIBRARY] Sub FlagSet(bit As Integer)
Error: Duplicate name
> RUN
[LIBRARY] Sub FlagSet(bit As Integer)
Error: Duplicate name
>
now the prog won't run but the error is bogus. A fresh reset

> ARMmite MMBasic Version 5.05.02
Copyright 2011-2018 Geoff Graham
Copyright 2016-2018 Peter Mather

> RUN
1545317906 20-12-2018 14:58:26 20-12-2018 14:58:26 1 1 4
1545317906 20-12-2018 14:58:26 20-12-2018 14:58:26 1 1 4
1545317906 20-12-2018 14:58:26 20-12-2018 14:58:26 1 1 4
1545317906 20-12-2018 14:58:26 20-12-2018 14:58:26 1 1 4
1545317906
>


but any error...

> ? 1.3/0
Error: Divide by zero
> RUN
[LIBRARY] Sub FlagSet(bit As Integer)
Error: Duplicate name
>


Edited by CaptainBoing 2018-12-22
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 05:02pm 20 Dec 2018
Copy link to clipboard 
Print this post

I think this fixes it

2018-12-21_031540_Armmite1.3.zip

It isn't a new bug but one that was introduced when I did the upgrade to Geoff's 5.05.01 codeEdited by matherp 2018-12-22
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 05:13pm 20 Dec 2018
Copy link to clipboard 
Print this post

yep that seems to have nailed it.

Thanks Peter
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3378
Posted: 12:29am 02 Mar 2019
Copy link to clipboard 
Print this post

If I have gotten the syntax right, it appears that the "interrupt on character" feature added to the serial OPEN command by Geoff with Micromite MMBasic Ver 5.05.02 Beta has not been migrated to the H7.

> open "com4:115200,1024,simfileInterrupt,=13" as #10
Error: Syntax
> Open "com4:115200,1024,simfileInterrupt,13" As #10
> close 10
>

The second instance, which doesn't have a syntax error, interrupts after 13 characters. The first is intended to interrupt on CR.

Would it be convenient to add this?

PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 08:18am 02 Mar 2019
Copy link to clipboard 
Print this post

  Quote  Would it be convenient to add this?

Geoff doesn't release source of Betas so I can't include it until the next release
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3378
Posted: 04:59pm 02 Mar 2019
Copy link to clipboard 
Print this post

Ok. I think this does what I want without an interrupt (following Grogster and CaptainBoing).
[code]
dim string serinLine, inB$
open "com4:115200,2048" as #10

do
if loc(#10) > 0 then ' character has arrived
pause 10 ' lots of characters at 115200 baud
do
inB$ = Input$(1, #10)
if inB$ <> chr$(13) and len(serinLine)<255 then serinLine = serinLine + inB$
loop while loc(#10) <> 0 and inB$ <> chr$(13)
print serinLine
serinLine=""
endif
loop
[/code]
Slightly different code should fold into my program.

PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3378
Posted: 04:59pm 07 Mar 2019
Copy link to clipboard 
Print this post

I'm looking to use pin 20 on the H7 (with backpack). setpin 20,din says it's not available:
> print mm.ver,mm.device$
5.0503 ARMmite H7
> list
> setpin 20,din
Error: Pin 20 is reserved on startup
>

The H7 manual indicates it should be.
20 ANALOG_C DIGITAL_IN DIGITAL_OUT SPI5-IN

I'm trying to just use pins on Connectors 8 & 9 on the H7. Should this pin be available?

Pins 19 & 21 are likewise reserved. Is SPI5 reserved or should the pins be available for general usage?
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 05:12pm 07 Mar 2019
Copy link to clipboard 
Print this post

  Quote  Pins 19 & 21 are likewise reserved. Is SPI5 reserved or should the pins be available for general usage?


On the Armmite H7 SPI5 is used for SPI displays, touch and SD cards so if you have any of those configured then the pin will not be available for other use. OPTION RESET and the pin should be available.
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3378
Posted: 05:34pm 07 Mar 2019
Copy link to clipboard 
Print this post

  matherp said  On the Armmite H7 SPI5 is used for SPI displays, touch and SD cards

Ok. I'm using the SD card on an SSD1963_4, so I guess that makes 19,20,21 unavailable. Fortunately, I haven't used 115 or 26 yet (CN9_27 & CN9_29), so I can use 115 and still have a pin to spare.

After (limited) testing, that works with all the pins on CN8 & CN9 allocated except 26.

PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025