Minimal instrument
LED blinker for the Red Pitaya has the following files:
├── block_design.tcl
├── config.yml
├── constraints.xdc
├── led_blinker.hpp
├── led_blinker.py
├── test.py
└── web
├── app.ts
├── control.ts
├── index.html
├── led_blinker.ts
└── main.css
Memory
Memory registers are specified in the instrument configuration file.
memory:
- name: control
offset: '0x60000000'
range: 4K
- name: status
offset: '0x50000000'
range: 4K
control_registers:
- led # defines a control register
status_registers:
- forty_two # defines a status register
Registers are accessible by their names from Tcl and C++.
FPGA
Block Design
The Vivado block design is generated by the file block_design.tcl
:
# Add PS and AXI Interconnect
set board_preset $board_path/config/board_preset.tcl
source $sdk_path/fpga/lib/starting_point.tcl
#source $sdk_path/fpga/lib/starting_point.tcl
# Add config and status registers
source $sdk_path/fpga/lib/ctl_sts.tcl
add_ctl_sts
# Connect LEDs to config register
create_bd_port -dir O -from 7 -to 0 led_o
connect_port_pin led_o [get_slice_pin [ctl_pin led] 7 0]
# Connect 42 to status register
connect_pins [get_constant_pin 42 32] [sts_pin forty_two]
The control and status IPs (ctl
and sts
) are connected to the port M_AXI_GP0
of the Zynq Processing System (ps_0
) via the AXI Interconnect (axi_mem_intercon_0
).
This connection is clocked with ps_0/FCLK_0
which has been defined to 50 MHz via the parameter fclk0
in the configuration file.
Cores
Cores must be specified in the instrument configuration file.
cores:
- fpga/cores/axi_ctl_register_v1_0
- fpga/cores/axi_sts_register_v1_0
- fpga/cores/dna_reader_v1_0
axi_ctl_register
and axi_sts_register
are used for communication between the Programmable Logic (PL) and the Processing System (PS) running Linux.
Both cores are accessible from Linux as memory-mapped regions.
C++ drivers
C++ Drivers must be specified in the instrument configuration file.
Below is the C++ driver led_blinker.hpp
:
#include <context.hpp>
class LedBlinker
{
public:
LedBlinker(Context& ctx)
: ctl(ctx.mm.get<mem::control>())
, sts(ctx.mm.get<mem::status>())
{}
void set_leds(uint32_t led_value) {
ctl.write<reg::led>(led_value);
}
uint32_t get_leds() {
return ctl.read<reg::led>();
}
void set_led(uint32_t index, bool status) {
ctl.write_bit_reg(reg::led, index, status);
}
uint32_t get_forty_two() {
return sts.read<reg::forty_two>();
}
private:
Memory<mem::control>& ctl;
Memory<mem::status>& sts;
};
Python
Python scripts are written in line with the Python API.
Driver
from koheron import command
class LedBlinker(object):
def __init__(self, client):
self.client = client
@command()
def set_leds(self, led_value):
pass
@command()
def get_leds(self, led_value):
return self.client.recv_uint32()
@command()
def set_led(self, index, status):
pass
@command()
def get_forty_two(self):
return self.client.recv_uint32()
Application
from koheron import connect
import os
import time
from led_blinker import LedBlinker
host = os.getenv('HOST','192.168.1.100')
client = connect(host, name='led-blinker')
driver = LedBlinker(client)
print(driver.get_forty_two())
print('Start blinking...')
for i in range(255):
driver.set_leds(i)
time.sleep(0.01)
TypeScript
TypeScript files are written in line with the TypeScript API.
Driver
class LedBlinker {
private driver: Driver;
private id: number;
private cmds: HashTable<ICommand>;
constructor (private client: Client) {
this.driver = this.client.getDriver('LedBlinker');
this.id = this.driver.id;
this.cmds = this.driver.getCmds();
}
getLeds(cb: (value: number) => void): void {
this.client.readUint32(Command(this.id, this.cmds['get_leds']),
(value) => {cb(value)});
}
setLed(index:number, status: boolean): void {
this.client.send(Command(this.id, this.cmds['set_led'], index, status));
}
}
Application
class App {
private driver: LedBlinker;
public control: Control;
constructor(window: Window, document: Document, ip: string) {
let client = new Client(ip, 5);
window.addEventListener('load', () => {
client.init( () => {
this.driver = new LedBlinker(client);
this.control = new Control(document, this.driver);
});
}, false);
window.onbeforeunload = () => { client.exit(); };
}
}
let app = new App(window, document, location.hostname);