Sunday 10 October 2021

ZX Spectrum Next z88dk banking example

The Spectrum Next's z80 processor can only directly address 64k of memory but the ZX Spectrum 128 and ZX Spectrun Next models are equipped with far more physical memory than this. 

Bank switching is used to access this extra memory.

This example explains how to implement bank switching in C code using z88DK compiler. 

https://github.com/pdj102/bankingExample

Monday 6 September 2021

z88dk adt p_forward_list demo

 Demo of how to use the z88dk adt p_forward_list

#include <stdio.h> 
#include <stdint.h>     // standard names for ints with no ambiguity 
#include <adt/p_forward_list.h>

static p_forward_list_t src;

typedef struct
{
    void *next;

    uint8_t v;
item_t;

int main()
{
    uint8_t l;

    item_t item1;
    item_t item2;
    item_t item3;

    item1.v = 1;
    item2.v = 2;
    item3.v = 3;

    item_t *item_ptr;

    p_forward_list_init(&src);

    printf("Push 1, 2, 3 to front\n");
    p_forward_list_push_front(&src,&item1);
    p_forward_list_push_front(&src,&item2);
    p_forward_list_push_front(&src,&item3);        

    l = p_forward_list_size(&src);
    printf("List length = %d\n"l);
    printf("Read items from list\n");

    for (item_ptr = p_forward_list_front(&src); item_ptritem_ptr = p_forward_list_next(item_ptr))
    {
        printf("Item = %d\n"item_ptr->v);
    }

    printf("Clear list\n"); 
    p_forward_list_clear(&src);
    l = p_forward_list_size(&src);
    printf("List length = %d\n"l);     

    printf("Push 1, 2, 3 to back\n");
    p_forward_list_push_back(&src,&item1);
    p_forward_list_push_back(&src,&item2);
    p_forward_list_push_back(&src,&item3);    

    for (item_ptr = p_forward_list_front(&src); item_ptritem_ptr = p_forward_list_next(item_ptr))
    {
        printf("Item = %d\n"item_ptr->v);
    }

    printf("Remove 2\n");
    p_forward_list_remove(&src,&item2);

    l = p_forward_list_size(&src);
    printf("List length = %d\n"l);
    printf("Read items from list\n");
    for (item_ptr = p_forward_list_front(&src); item_ptritem_ptr = p_forward_list_next(item_ptr))
    {
        printf("Item = %d\n"item_ptr->v);
    }

    while(1)
    {

    }

    return 0;
}

 

Sunday 5 September 2021

ZX Spectrum Next Hello World C program using z88dk

Hello World C program for the ZX Spectrum Next using the z88dk compiler.

Z88DK

Z88DK is a collection of software development tools that targets the 8080 and z80 family of machines. It allows development of programs in C, assembly language or any mixture of the two. What makes z88dk unique is its ease of use, built-in support for many z80 machines, including ZX Spectrum Next, and its extensive set of assembly language library subroutines implementing the C standard and extensions.

The Z88DK offers several C Run Times (CRT) that can be selected using -startup at compile time. These CRTs provide the initialisation code that is called before main(). Some of them provide a simple tty device which supports controls codes such as \x16nn move cursor to X,Y.

NB when installing z88dk on Windows you need to set up the environment variables

  1. create a environment variable to point to the z88dk root folder e.g. called z88dk
  2. include z88dk\bin in your PATH 
  3. set Z80_OZFILES to point to \lib e.g. $Env:Z80_OZFILES=$Env:z88dk+"\Lib\"
  4. ZCCCFG to point to the config folder e.g. $Env:ZCCCFG=$Env:z88dk+"\Lib\Config"

Hello World C program

The following program prints "Hello World" near the middle of the screen and then loops forever changing the border between red and yellow. 

The resultant .nex file can be loaded by a ZX Spectrum emulator such as CSpect or copied over and run on real ZX Spectrum Next hardware.

/* =========================================================================
    ZX Spectrum Next Hello World C program
    Compile using z88dk
    zcc +zxn -vn -SO3 -clib=sdcc_iy -startup=1 --max-allocs-per-node200000 .\helloworldSpectumNext.c -create-app -subtype=nex

    +zxn            target ZX Spectrum Next
    -vn             no verbose
    -SO3            set optimisation level 3
    -clib           use sdcc_iy library (and use the recommended zsdcc compiler which produces smaller code)
    -start          set the C Run Time. 1 is standard 32 column display tty_z88dk terminal
    --max-allocs-per-node   controls how deeply zsdcc looks at code alternatives
    -create-app     run the program to create an executable that can be run by an emulator
    -subtype=nex    Create a nex file executable
*/

#include <arch/zxn.h>   // ZX Spectrum Next architecture specfic functions
#include <stdio.h>      

// Define some macros to make use of tty_z88dk control codes
// Program must be compiled with a CRT that supports tty_z88dk e.g. -startup=1
#define printInk(k)          printf("\x10%c"'0'+(k))
#define printPaper(k)        printf("\x11%c"'0'+(k))
#define printAt(rowcol)    printf("\x16%c%c", (col)+1, (row)+1)

int main()
{
    printAt(10,10);                 // move cursor 
    puts("Hello World!");       

    while(1) {                      // loop for ever
            zx_border(INK_RED);     // set border red
            zx_border(INK_YELLOW);  // set border yellow
    };
    
    return 0;
}
 

Sunday 8 August 2021

Connecting a LoLin NodeMcu v3 IoT to the Azure IoT Hub using the Arduino IDE

An overview of how to connect a LoLin NodeMCU v3 IoT device to the Azure IoT Hub using the Arduino IDE.

The Azure IoT Hub provides a cloud-hosted solution back-end to connect backend applications with IoT devices.

The LoLin NodeMCU v3 device is a wireless IoT device based on the ESP8266 microchip. For more info see First Impressions of the LoLin MCUv3 

The high-level steps to connect the LoLin NodeMCU IoT to the Azure IoT cloud are

  1. Create an Azure IoT Hub service (Azure offers a basic free version)
  2. Manually register a device with your Azure IoT Hub service (easily done in the Azure portal)
  3. Install the Arduino IDE and install the Azure IoT libraries via the Arduino IDE library manager
  4. Use the Azure IoT device SDK for C to write a program for the device to connect to your Azure IoT Hub service or use the Microsoft provided sample program.

For steps 1 to 3 refer to the following guide for step by step instructions to setup an Azure IoT Hub, register a LoLin device, setup the Arduino libraries and run your first IoT program

 

Microsoft Azure IoT C SDK

Microsoft publish a C SDK that supports a wide range of IoT devices including the LoLin NodeMCU. Developers can use this C SDK to develop programs to connect devices to the Azure IoT Hub.

The LoLin NodeMCU is based on the ESP8266 Microcontroller (MCU) and is what Microsoft call a constrained device in that it has comparatively limited resources, such as memory, compared to devices based on a CPU.

The Azure IoT C SDK includes a version that is optimised to run on constrained devices. For example, it is single threaded whereas some of the functions in the unconstrained version will spin up seperate threads to complete jobs in the background.

These C libraries need to be installed in the Arduino IDE environment using its Library Manager as explained in the guide above. Once installed we can include these libraries in our programs with

#include <AzureIoTHub.h>

Azure IoT SDK for C developer documentation 

Microsoft publish a detailed developer how-to guide for the Azure IoT device SDK which explains how to use the API with examples. Find it here Dev guide for the Azure IoT device SDK for C     

The Azure IoT SDK reference provides detailed information on the C library functions and data structures and can be found on GitHub here Github for Azure IoT C SDKs and Libraries

Sample program

Microsoft provide a sample program 'iothub_ll_telemetry_sample' to demonstrate use of the Azure IoT SDK on the ESP8266. 

The key functions called by the demo program are

esp8266_sample_init(const char* ssid, const char* password)
Connect to wLAN
 
Initialise the IoTHub client system
 
device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(connectionString, protocol)
Creates a IoT Hub client for communication with an existing IoT Hub using the specified connection string parameter.
 
Set the Azure Server certificate used to validate TLS connection to iothub
 
Creates a new IoT hub message from a null terminated string. The type of the message will be set to IOTHUBMESSAGE_STRING
 
Asynchronous call to send the message specified by eventMessageHandle
The call back mesage 'send_confirm_callback' is called with the results of the message transmission. 
 
This function MUST be called by the user so work (sending/receiving data on the wire, computing and enforcing timeout controls, managing the connection to the IoT Hub) can be done by the IoTHubClient. The recommended call frequency is at least once every 100 milliseconds.
 
In the demo program it attempts to send several messages and once sent counts the number of times the call_back function is called. Once the number of call backs equals the total number of messages sent it exits. Throughout it is calling the Do Work function.

Saturday 20 February 2021

Ableton Live TR-8 Setup

 How to setup the Roland TR-8 with Ableton Live

Step 1 - Cabling

Connect the TR-8 to your sound card and PC
  • Connect a USB cable to the PC and TR-8 for MIDI control
  • Connect the TR-8 left and right mix outputs to sound card inputs i.e. channels 1 and 2

Step 2 - Live MIDI Preferences

Next configure the TR-8 in Live's MIDI preferences
 
 
Live's MIDI preferences
 
To be able to record MIDI input from the TR-8 ensure Input: TR-8 Track and Sync are on

To be able to send MIDI from an ableton track to the TR-8 ensure Output: TR-8 Track is on

If you want the TR-8 to start and stop playing an internal pattern when Ableton starts and stops playback ensure TR-8 Output: Sync is on. 

If you only want the TR-8 to respond to MIDI input from Live and not start playing an internal pattern  when Ableton starts playback leave TR-8 Output: Sync off. 

Step 3 - Sending MIDI from Live track to TR-8

To send the MIDI from a Live track to the TR-8 a MIDI track needs to be configured to send its MIDI output to the TR-8 on the correct MIDI channel. To do this in the MIDI track's in/out section set
  • MIDI to TR-8
  • MIDI channel to Ch. 10 or whatever MIDI channel your TR-8 is configured to

Step 4 - Receiving audio sound from the TR-8 

To hear the audio from the TR-8 in Live an audio track needs to be configured to receive the TR-8's audio as its input.  To do this in the audio track's in/out section set 
  • Audio From Input Type to Ext. In (your sound card)
  • Audio From Input channel to the sound card input channels e.g. 1/2

Now when you play a MIDI note on the MIDI track configured in step 3 (play C1 for a kick) you should hear the TR-8 audio on the audio track configured in step 4. 

Step 5 - Alternative to steps 3 and 4 - Ext. Instrument

As an alternative to steps 3 and 4 the Ext. Instrument device can be used on a single MIDI track so there is no need for seperate MIDI and Audio tracks.
  • Place the Ext. Instrument device on a MIDI track
  • Set MIDI To to the TR-8 and channel to Ch.10 (or whatever MIDI channel your TR-8 is configured to)
  • Set Audio From to the input channels e.g. 1/2
 Now when you play a MIDI note on the MIDI track you should hear the TR-8 audio 

How to record TR-8 audio in a Live track

To record audio from the TR-8 an audio track needs to be configured to receive the TR-8s audio as an input, see step 4 above. 

To avoid a noticable delay in the recording turn the Monitor OFF. The timing of the audio will be much more accurate but the recorded audio will not be processed by any devices on the audio track. 

If you record with the Monitor set to In or Auto the recorded audio will have a noticable delay when played back as the drums will play slightly out of time. This can be manually corrected by adjusting the start point of the clip but the problem can be avoided by setting Monitor OFF before recording. 

 

Sunday 7 February 2021

4bit Juno ALU

The 4bit Juno ALU is based around an 74 series 181 ALU arithmetic logic chip which implements mathematical and logical operations. The '181 was used in many early minicomputers like the NOVA and PDP-11. 

The mathematical operations include addition, subtration with or without carry and the logical operations include logical ∧ AND, NAND, ∨ OR, NOR, ⊕ XOR and shift. 

The inputs to the ALU are the DR register and the data bus.  Operations are performed by loading the DR register with the first operand and then placing the second operand on the data bus. The output of the operation is stored in A register.

The Carry input is selected using the carry multiplexer and can be (0) zero, (1) one or (2) the carry bit of the status register.

The Carry and Comparator result of the operation can be saved to the status register using LD_Carry and LD_Comparator. 



 

Saturday 30 January 2021

Micro code controller

Each CPU instruction such as "LDA <address>" is implemented as a sequence of micro code operations. 

Each micro code operation sets the CPU control signals high or low and holds them for a clock cycle before moving to the next micro code operation in the sequnce. 

These CPU control signals are encoded as data in ROM chips. A '1' sets the control signal high and '0' sets the control signal low. 

The ROM contents are addressed using an 8-bit address, 4 bits for the instruction being executed plus 4 bits for the step in the micro code sequence. Therefore, the Juno PC supports 16 CPU instructions and each instruction can be up to 16 steps in length.

To support the number of control signals needed several 8-bit ROM chips are used. 

Instruction Register

The current instuction being executed is held in the 4-bit Instruction Register (IR). Each instuction has a unique number between 0 and 15.For example, the NOP instuction is instuction 0.

At the start of every instruction the Program Counter (PC) register must hold the address of the instruction to be executed and the first step of the micro code sequence is to load the IR with the instruction pointed to by PC. 

The micro code controller will then step through the sequence of operations for the instruction. 

NB on starting a new instruction IR will actually hold the previous instruction and execute step 0 which will load IR with the instruction at address PC.

Micro code step sequencer

The micro code step sequencer is implemented using a 4-bit counter. To start a new instruction the counter is reset to zero by the previous instruction. The counter is then incremented by the clock until it is reaches the last step in the sequence. The last step in sequence must reset the counter to zero using the uCounterRest control signal to start the next intruction.

The counter is implemented using a 74HC393 counter which features a clock input that increments the counter on a falling edge. A clock cycle is therefore from one falling edge to the next and the control signals are held for the duration of this clock cycle. 

The CPU control signals for load, or write, operations are logically AND with the clock signal so that control signal goes positive half way through the clock cycle. For example, registers are implemented using postive edge triggered chips such as the 74HC574.

This control sequence ensures there is time for the control signals and digital circuits to stabalise before performing the load / write actions. 




Clock and basic timing operation

A clock signal is a periodic signal that switches between high and low and is used to coordinate the actions of digital circuits.

A clock cycle is the time between two rising edges and consists of

  • A - a fast low to high rising edge  
  • B - a high state
  • C - a fast high to low falling edge
  • D - a low state

Sequential digital circuits can be designed to be 

  • tiggered by either a rising or falling edge or 
  • to be active during a high or low level

In this way the operation of a CPU can be contolled and co-ordinated. For example, to load a register with the contents from a memory address location the clock can co-ordinate the operation as follows:

  1. on the falling edge the CPU 'micro code controller' enables the output of the Memory Address register and the memory address starts to flow over the address bus to the memory chip. 
  2. The memory chip outputs the addressed data onto the data bus
  3. Initially, both the memory address and data output are unstable but quickly stabalise and the data on the data bus becomes valid
  4. Next, on the rising clock edge the CPU 'micro code controller' triggers the register to load the now valid data presented on the data bus

To achieve this timing the CPU control signals for load, or write, operations are logically AND with the clock signal so that control signal goes positive half way through the clock cycle. For example, registers are implemented using postive edge triggered chips such as the 74HC574.