We are closed from December 18, 2024 to January 5, 2025. Orders placed during this time will be processed starting on January 6, 2025.

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]

LED Blinker Vivado Block Design

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);

See also

[email protected]