Friday, January 31, 2025

PIO (Programmable Input/Output)





A PIO é um dos periféricos mais interessantes e único do rppico (Raspberry pi Pico) porque ele levou a comunicação pelos pinos GPIOs do microcontrolador a outro nível, e um nivel muito elevado de sofisticação e desempenho.


A PIO tem quatro máquinas de estado, eu acredito que todos que tenham interesse por esse artigo deve saber oque é uma máquina de estado, por isso não vou explicar em profundidade esse quesito.


A máquina de estado da PIO é totalmente independente da cpu e essa característica é muito importante para muitas aplicações, porque você põe dados e ou retira dados dos pinos independentemente da cpu isso significa que o tempo entre coletar o dado no pino e disponibiliza-lo na memoria interna e ou executar alguma outra ação é muito menor do que se fosse a cpu lendo o dado no pino, esse é um dos motivos pelo qual pipocou na internet muitos projetos usando o rppico gerando sinais de vídeo.


As máquinas de estado são pequenos “processadores” dedicados a ler e ou escrever nos pinos, e com isso houve a necessidade de ter um programa para elas, assim uma linguagem para isso. A linguagem usada para programar a PIO é uma linguagem assembly específica chamada PIO Assembly.


O que é PIO Assembly?

A PIO Assembly é uma linguagem de baixo nível usada para escrever programas que rodam diretamente nas máquinas de estado (state machines) da PIO. Cada máquina de estado da PIO pode executar um programa independente, permitindo criar protocolos de comunicação personalizados, controlar GPIOs com precisão de tempo e muito mais.

Esse é um exemplo de programa em assembly para fazer um led piscar.


.program blink
    set pindirs, 1    ; Define o pino como saída

again:
    set pins, 1 [31]      ; Liga o pino (HIGH)
    set pins, 0 [31]      ; Desliga o pino (LOW)
    jmp again         ; Repete o loop

Observem que o programa não tem um delay entre as linhas que ligam e desligam o led, essa é uma das características muito interessantes do assembler da PIO, pois como ele é totalmente independente da cpu o que é feito nessa situação é configurar a máquina de estado para um clock bem baixo.

Vamos entender tudo isso:

set pins, 1 [31] 



Essa linha significa o seguinte, set pins, 1 é fácil de saber oque faz, esse comando assembly diz para por o pino apontado por pins com o valor 1 ou seja 3,3V deve aparecer no pino em questão, agora a diretiva [31] é que é muito interessante, pois ela diz que o programa ficará parado por 31 ciclos do clock, UAUUUUUU… que maravilha e a cpu não ficou parada por isso. Então imagina que você tenha configurado a maquina de estado para um clock com um ciclo de 5ms(mili segundos) 5 x 31 = 155ms esse é o tempo que o led ficará apagado e depois aceso, ou seja o led vai piscar a uma taxa de aproximadamente 6 vezes por segundo, mas sua cpu está rodando a 133MHz lembre-se.
E tem mais sobre isso ainda, cada linha de código no assembly da PIO é totalmente executada em apenas 1 ciclo de clock, com isso fica muito fácil de fazer um program muito deterministico em relação ao tempo de execução das tarefas.

Características da PIO no Raspberry Pi Pico

  1. Blocos de PIO:

    • O RP2040 possui 2 blocos de PIO independentes, cada um com 4 máquinas de estado (state machines), totalizando 8 máquinas de estado programáveis.

  2. Máquinas de Estado (State Machines):

    • Cada máquina de estado é um processador independente que executa um programa PIO.

    • As máquinas de estado podem ser programadas para implementar protocolos de comunicação personalizados ou manipular sinais de GPIO de forma altamente eficiente.

  3. Instruções PIO:

    • A PIO possui um conjunto de 9 instruções básicas que podem ser usadas para criar programas personalizados.

    • As instruções incluem operações como leitura/escrita de GPIO, manipulação de registradores, controle de fluxo (loops e branches), e sincronização com clocks externos.

    • O conjunto de instruções é simples, mas poderoso, permitindo a criação de protocolos complexos.

  4. Flexibilidade de GPIO:

    • As máquinas de estado da PIO podem controlar qualquer pino GPIO do RP2040.

    • Isso permite que você use a PIO para implementar protocolos personalizados em praticamente qualquer pino do Pico.

  5. Velocidade e Precisão:

    • A PIO opera de forma independente da CPU principal, permitindo operações de alta velocidade e baixa latência.

    • Ela pode manipular sinais com precisão de 1 ciclo de clock, o que é ideal para protocolos de comunicação rápidos ou controle de dispositivos sensíveis ao tempo.

  1. Protocolos Suportados:

    • A PIO pode ser usada para implementar uma variedade de protocolos de comunicação, como:

      • Protocolos seriais: UART, I2C, SPI, 1-Wire, etc.

      • Protocolos de controle: PWM, controle de LEDs (WS2812/NeoPixel), controle de motores, etc.

      • Protocolos personalizados: Você pode criar seu próprio protocolo para atender às necessidades específicas do seu projeto.

  2. Memória de Programa:

    • Cada bloco de PIO possui uma memória de programa compartilhada de 32 instruções.

    • Como há 4 máquinas de estado por bloco, é possível compartilhar o mesmo código entre várias máquinas ou programar cada máquina de forma independente.

  3. Clock Divisor:

    • Cada máquina de estado pode ser configurada com um divisor de clock para ajustar a velocidade de operação.

    • Isso permite que a PIO opere em velocidades mais baixas, se necessário, para compatibilidade com dispositivos externos.

  4. Interrupções:

    • A PIO pode gerar interrupções para a CPU principal, permitindo sincronização entre operações de hardware e software.

  5. Exemplos de Uso:

    • Implementação de protocolos não suportados nativamente pelo RP2040 (ex: DPI, VGA, MIDI).

    • Controle de LEDs endereçáveis (ex: WS2812/NeoPixel).

    • Geração de sinais PWM de alta precisão.

    • Leitura de sensores com protocolos personalizados.

Esse é o que eu queria dizer nesse artigo, não vou entrar em detalhes de como configurar o SDK do rppico no Visual Studio Code porque tem uma tonelada de tutoriais na internet explicando como fazê-lo e acredite-me é simples.


No próximo artigo entrarei em detalhes da programação da PIO.


Até lá.


Paulo da Silva (pgordão).

Técnico em Eletrônica.

Analista de Sistemas.

31/JAN/2025


Wednesday, July 12, 2023

 New Power Key to raspberry PI 

This new version has a tip120 to driver the output power, the tip127, but the great change in this version is the step Down I designed 2 schematics one using a stepDOWN converter  in the circuit input and another one in the circuit output, the differences betwen them is that you can change the tip127 to another smaller transistor because the current in the input of the converter will be smaller, I left the tip127 in both design but this is not mandatory.

As raspberry PI needs 5v with 3amp we have 15w in the output of the stepdown so in the input we will need only 1,25amp this permits we use a smaller transistor to substute tip127, or if you continue using tip127 you can use it without heatsink.

Fig.01
 
 
 

Friday, April 14, 2023

This time the project is not for an old computer, the target is the raspberry pi, I saw many posts about the lack of a switch to turn on and off a raspberry pi and when you do a shutdown you never know when you can remove the power supply.

Recently I came up with this problem again so I decided to solve it and the result is the design below.


The connector J1 has the following signals:
Pin1 - 5volts from power supply.
Pin2 - GND from power supply

The connector J1 has the following signals:
Pin1 - 5volts to raspiberry pi
Pin2 - GND to raspiberry PI
Pin3 - GPIO14 from raspberry PI

Description:

When SW1 is pressed the capacitor C1 starts to charge and at the same time the transistor Q2 turn on the transistor Q1 so raspberry pi turn ON, while the raspberry are turning ON, the voltage for raspberry is manteined by cap C1, the time is ON is about 10 seconds, after this the voltage is mantained by GPIO14 once raspberry gets on line. If you experience some problems with this time you can change the capacitor C1 for another one with more capacitance.

When you shutdown raspberry PI it will turn off GPIO14 the signal that mantain the power ON, so transistor Q2 will turn off transistor Q1 and respberry PI stops receive 5volts, and you can presse SW1 again to turn it on.

I tested with a raspberry PI 3 and worked like a charm.

Using this with raspberry PI 3 the heatsink stayed cool, the current stayed about 550mA all the time with only the operating system running and samba.

I believe that the raspberry PI 4 will give us another scenario because it consumes more current and takes longer to turn on and off.



Tuesday, July 12, 2022

The brightness of the LED more difficult.

I spent the last week fixing several problems to make the CH376S work because the datasheet do not help so much, or maybe I lost the part that explained this.

The first thing I did and the module behavior changed was to tie the RST to another peripherals RST, the datasheet is not clear about the RST somewhere I read that the RST is an output, on www every schema I found RST was left disconnected, but for me the 8bitstack code (z80 playground) only started to recognize the CH376S when I joined the RST of the CH376S together with the RST of other peripherals, but sometimes it was not detected, 

I put a delay between reset and configuration and it did not solved the problem, 

I was suspicious that the parallel configuration method should only work with the chip running at 5Volt because the instable behavior did not made sense and the schematic for parallel config was with 5volts, só I opened the pin number 9 of the chip and put a 01nF capacitor to ground and take off lm1117 and I joined input voltage with output voltage together.

VOILÁ !!!... it worked now everytime I reset the module is detected buy the software, I could take off all delays and tricks that I put in code to try detect it and it continue to work. The led of the module are shining now!!!


#Z80
#CPM
#ASSEMBLER
#CH376S
#8255
#16C550
#I2C

Wednesday, July 6, 2022



 After a long long time I really decided to implement my z80 computer, above it is the picture of the system board I have been working on it.

This project is a Z80 based computer designed to run as a MSX. It is a work-in-progress, and the current specs are:

  • 32K of ROM (EEPROM for ease of reprogramming)
  • 64K of RAM
  • A very basic machine code monitor and disassembler in ROM
  • BBC Basic for Z80
  • Serial I/O via an TL16C550CN UART
  • Serial I2C LCD1602 only for fun

The intention is to work towards a fully functioning MSX1 clone , with a TMS9938 video chip and AY-8912 sound.

I found a work from Dean Belfield that has the same proposal I was thinking to do, an MSX homemade, so I am continuing what he has been started.

The monitor program that helps in develoment of interfaces to z80 was the tool I am using for this job, I recently implemented the following:

1 - A help command to show in the terminal the options system has.

2 - Uart with TL16C550CN the chip I already have in my lab.

3 - MSX logic to access rom and ram by slot mecanism.

4 -  An I2C driver for the z80.

5 - The code to deal with LCD1602

The I2C and LCD I did just for fun, because MSX does not needs it, although I do not decided if the access to system files will be by sdcard(I2C) or by CH376B, sdcard give me advantage of knowledge because I aready did a system using  it, but it is a hard work, on the other hand CH376B is só easy to use but I had never used it, anyway this is the next step, see you!



 



 

Monday, October 3, 2016

keyboard

Hi all,

Now its time to talk about the keyboard, I did a little search in all my city's shop waste to find an used piece, and after a long time I found one, it belongued to a POS(Point Of Sale) it is from Itautec model PDV 54 keys and i payed only $5 bucks.
It will be enough for my project as I am thinking to make monitor's program to help in programming the z80.


At the right side you can see the part that will be used to input program z80's memories.
The keys 0 .. F (hexadecimal ) input







The keyboard's schematic.



I did some modifications to the printed board to facilitate the key reading, and in the end it is like the schematic above.


Thursday, September 29, 2016

The z80 system clock

      
My z80 system will be started in a section named OpenZ80, the clock, that I had so many doubts about it, as I used to work with moderns microcontrollers and clock does not need to be so clear, and I read that z80 needs a clean clock and reset, I decided to use an attiny15L that I have some pieces here. This chip will provide several clocks for the system and configuring 2 pins it is possible to change betwen them. The clock values are: 12Mhz, 6Mhz, 3Mhz and 1,6Mhz no need to say that all of them will not have the precise value, because the attiny15l has a pll that generate 25Mhz that is divided to get these values Another feature is: 1 - the reset pulse to the z80, this reset will maintain the z80 for a long time in logic level zero when the power supply is turned on. 2 - led blinking, this is just to sinalize that the system is on, Image 01 - Clock Attiny15L - Assembler code to generate: clock, reset and blink led
 
; Program....: reset.asm
; Description: Z80 reset, clock 1,6Mhz, 3,2Mhz, 6,4Mhz or 12,8Mhz
; Author.....: Paulo da Silva
; Date.......: 26/09/2016
; 
; Attiny15L
;        +----+
;   rst--|    |-- vcc;
; cfg1 --|    |-- led blink
; cfg2 --|    |-- z80 clock
;   gnd--|    |-- z80 reset
;        +----+
;                                           
;    cfg2 cfg1                                      
;     0    0  ->   12,8Mhz                           
;     0    1  ->    6,4Mhz                  
;     1    0  ->    3,2Mhz                      
;     1    1  ->    1,6Mhz   
;
; Assembler: avra version 1.3.0 build 1
; Command..: avra reset.asm
.nolist
.include "/usr/share/avra/tn15def.inc"
.list
;==============
; Declarations
; PB0 - reset for z80
; PB1 - z80`s clock
; PB2 - led blink
; PB3 - Clock`s Configuration bit 1 (cfg1)
; PB4 - Clock`s Configuration bit 2 (cfg2)
;=================
; Variable Declarations
.equ OSCCAL_val = 0x6F  ; Calibrate
.def cseg       = r21  
.cseg      ; Code segment.
; Start of Program
.org    0
 rjmp Init   ; First line executed
 reti     ; IRQ0 handler
 reti     ; Pin change handler
 rjmp timer1CM  ; Timer1 compare match
 reti     ; Timer1 overflow handler
 rjmp timer0;  ; Timer0 overflow handler    
 reti     ; Eeprom Ready handler
 reti     ; Analog Comparator handler
 reti     ; ADC Conversion Handler
;============
Init:
 ; writing calibration byte to the OSCCAL Register.
 ldi     r16, OSCCAL_val
 out     OSCCAL, r16       
 nop
 nop
 ;Analogue comparator initialization
 ldi      r16, 0b10000000  ; Disable analogue comparator
 out      ACSR, r16
 ;PORTB initialization
 ldi      r16, 0b00000111  ; 1 = output e 0 =input1/6
 out      DDRB, r16    ; pb0 and pb1 = output pb2 = input
 ldi      r16, 0b11111000
 out      PortB, r16
 ;Timer initialization
 ldi      r16, 0x05   ; Timer 0 rolls over at 1.6MHz/1024/256 = 6.1Hz
 out      TCCR0, r16
 
 ;timer 1
 in    r16, PinB   ; Input port b to read clock configuration
 andi  r16, 0b00011000          ; pb3 and pb4
 cpi   r16, 0b00000000  ; 00 = 12,847Mhz
 brne  test6mhz
 ldi   r16, 0b10010001  ; 12Mhz
 rjmp  init2 
test6mhz: 
 cpi   r16, 0b00001000  ; 01 = 6Mhz
 brne  test3mhz
 ldi   r16, 0b10010010  ; 6,396 Mhz
 rjmp  init2  
test3mhz: 
 cpi   r16, 0b00010000  ; 10 = 3Mhz
 brne  test1mhz
 ldi   r16, 0b10010011  ; 3,210Mhz
 rjmp   init2
test1mhz: 
 ldi   r16, 0b10010100  ; 1,605Mhz
init2:
 out   TCCR1, r16
 ldi   r16, 0b00000000
 out   TCNT1, r16
 
 ldi      r16, $02  ;  Enable TOVF0
 out      TIMSK, r16  
 ldi      cseg, $01  ; Start at segment
 ldi      r17, 0x00
 ldi      r16, 0x00
 sei                  ; Enable Interrupts          
;======================
; Main body of program:
Main:            
loopRst:
 cbi  PortB, pb0 
 cpi  r16, 6  ; Wait some time here before to raise z80's reset line 
 brne loopRst
 sbi  PortB, pb0
blink:
 ;blink a led
 SBRS    r16, 0  ;2 Skip next instruction if bit0 = 1
 SBI     PORTB, pb2 ;2 Turn LED ON if bit0 = 0
 SBRC    r16, 0  ;2 Skip next instruction if bit0 = 0
 CBI     PORTB, pb2 ;2 Turn LED OFF if bit0 = 1
 rjmp    blink   ;2 loops back to the start of Main
 
timer0:
 inc  r16   ;Increment and will be used to blink a led
 reti
    
timer1CM:
This is tested !!! :) Enjoy