You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+42-17Lines changed: 42 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,8 +59,10 @@ These commands must be run when the running status is `STOPPED`.
59
59
*`get <address (in hex)>` - Gets instruction at address. Returns output word and number of clock cycles separated by a space, in same format as `set`.
60
60
*`run` - Used to hardware start a programmed sequence (ie waits for external trigger before processing first instruction).
61
61
*`swr` - Used to software start a programmed sequence (ie do not wait for a hardware trigger at sequence start).
62
-
*`adm <number of instructions (in hex)>` - Enters mode for adding pulse instructions in binary.
63
-
* The number of instructions must be specified with the command. The Pi Pico will then wait for that enough bytes to fill that many instructions (6 times the number of instructions) to be read, and will not respond during this time unless there is an error. This mode can not be be terminated until that many bytes are read.
62
+
*`adm <starting instruction address (in hex)> <number of instructions (in hex)>` - Enters mode for adding pulse instructions in binary.
63
+
* This command over-writes any existing instructions in memory. The starting instruction address specifies where to insert the block of instructions. This is generally set to 0 to write a complete instruction set from scratch.
64
+
* The number of instructions must be specified with the command, which is used to determine the total number of bytes to be read (6 6 times the number of instructions).
65
+
* This command returns `ready\r\n` to signify it is ready for binary data. The Pico will then read the total number of bytes. This mode can not be terminated until that many bytes are read.
64
66
* Each instruction is specified by a 16 bit unsigned integer (little Endian, output 15 is most significant) specifying the state of the outputs and a 32 bit unsigned integer (little Endian) specifying the number of clock cycles.
65
67
* The number of clock cycles sets how long this state is held before the next instruction.
66
68
* If the number of clock cycles is 0, this indicates an indefinite wait.
@@ -85,27 +87,50 @@ The basis of the functionality for this serial interface was developed by Carter
85
87
## Clock Sync
86
88
Firmware supports the use of an external clock. This prevents any significant phase slip between a pseudoclock and this digital output controller if their clocks are phase synchronous. Without external buffering hardware, clock must be LVCMOS compatible.
87
89
88
-
## Example:
89
-
Below program sets one output high for 1 microsecond, then low while setting the next output high for 1 microsecond (64 in hex = 100 in decimal) for 6 outputs, then stopping:
90
+
## Examples:
91
+
Below python script sets one output high for 1 microsecond, then low while setting the next output high for 1 microsecond (64 in hex = 100 in decimal) for 6 outputs, then stopping. `do` is a pyserial handle to the pico.
This is a python script that employs the binary write `adm` command.
110
+
In order to function correctly, the data to be written must be in a numpy structured array where each column dtype can be specified uniquely.
111
+
Below assumes the `bits` and `cycles` are 1-D arrays that have already been created.
112
+
It also assumes `do` is a pyserial handle to the device.
113
+
114
+
```python
115
+
data = np.zeros(len(bits), dtype=[('bits', 'u2'), ('cycles','u4')])
116
+
data['bits'] = bits
117
+
data['cycles'] = cycles
118
+
119
+
serial_buffer = data.tobytes()
120
+
121
+
do.write(f'adm 0 {len(data):x}\r\n'.encode())
122
+
resp = do.readline().decode()
123
+
assert resp =='ready\r\n', f'Not ready for binary data. Response was {repr(resp)}'
124
+
do.write(serial_buffer)
125
+
resp = do.readline().decode()
126
+
if resp !='ok\r\n':
127
+
# if response not ok, probably more than one line, read them all
128
+
# done this way to prevent readlines timeout for standard operation
129
+
extra_resp = do.readlines()
130
+
resp +=''.join([st.decode() for st in extra_resp])
131
+
print(f'Write had errors. Response was {repr(resp)}')
132
+
```
133
+
109
134
## Compiling the firmware
110
135
111
136
If you want to make changes to the firmware, or want to compile it yourself (because you don't trust binary blobs from the internet), we provide a docker configuration to help you do that.
// Check that the instructions will fit in the do_cmds array
530
-
if(inst_count+do_cmd_count >= MAX_DO_CMDS-3){
531
-
fast_serial_printf("Too many DO commands (%d + %d). Please use resources more efficiently or increase MAX_DO_CMDS and recompile.\r\n", do_cmd_count, inst_count);
531
+
elseif(inst_count+start_addr>MAX_INSTR){
532
+
fast_serial_printf("Invalid address and/or too many instructions (%d + %d).\r\n", start_addr, inst_count);
533
+
continue;
532
534
}
535
+
else{
536
+
fast_serial_printf("ready\r\n");
537
+
}
538
+
539
+
// reset do_cmd_count to start_address
540
+
do_cmd_count=start_addr*2;
541
+
542
+
uint32_treps_error_count=0;
543
+
uint32_tlast_reps_error_idx=0;
533
544
534
545
// It takes 6 bytes to describe an instruction: 2 bytes for values, 4 bytes for time
535
546
uint32_tinst_per_buffer=SERIAL_BUFFER_SIZE / 6;
@@ -545,7 +556,9 @@ int main(){
545
556
| (serial_buf[6*i+3] << 8)
546
557
| serial_buf[6*i+2]);
547
558
if(reps<5&&reps!=0){
548
-
fast_serial_printf("Reps must be 0 or greater than 4, got %x\r\n", reps);
559
+
reps_error_count++;
560
+
last_reps_error_idx= (do_cmd_count+1) / 2;
561
+
reps=0;
549
562
}
550
563
if(reps!=0){
551
564
reps-=4;
@@ -569,7 +582,9 @@ int main(){
569
582
| (serial_buf[6*i+3] << 8)
570
583
| serial_buf[6*i+2]);
571
584
if(reps<5&&reps!=0){
572
-
fast_serial_printf("Reps must be 0 or greater than 4, got %x\r\n", reps);
585
+
reps_error_count++;
586
+
last_reps_error_idx= (do_cmd_count+1) / 2;
587
+
reps=0;
573
588
}
574
589
if(reps!=0){
575
590
reps-=4;
@@ -579,7 +594,12 @@ int main(){
579
594
}
580
595
}
581
596
582
-
fast_serial_printf("ok\r\n");
597
+
if(reps_error_count>0){
598
+
fast_serial_printf("Invalid number of reps in %d instructions, most recent error at instruction %d. Setting reps to zero for these instructions.\r\n", reps_error_count, last_reps_error_idx);
599
+
}
600
+
else{
601
+
fast_serial_printf("ok\r\n");
602
+
}
583
603
}
584
604
// Dump command: print the currently loaded buffered outputs
0 commit comments