Author Topic: [CH32V003] The easiest way to use port C/D as INPUT and OUTPUT in the same time?  (Read 1091 times)

0 Members and 1 Guest are viewing this topic.

Offline pancioTopic starter

  • Newbie
  • Posts: 5
  • Country: pl
Hi,

Im working on project with CH32V003 which is connected directly to microprocessor's 6502 data bus... I need to read and inject some data from/to databus in proper time (based on additional signals like R/W, decoded address). My question is: Is possible to use the same port (e.g. C) in input and output mode? I tried code as below and reading data from bus working fine but writing to bus not:

Code: [Select]
// Reading data directly from PORTC and sending on SERIAL in hex format.
// D3: (D5_is_pressed) chip select
// D4: (RW_low) - Read/Write (active low)

// Could be defined here, or in the processor defines.
#define SYSTEM_CORE_CLOCK 48000000
#define APB_CLOCK SYSTEM_CORE_CLOCK

#include "ch32v003fun.h"
#include <stdio.h>

#include "ch32v003_GPIO_branchless.h"

int main()
{
SystemInit48HSI();
// SetupUART( UART_BRR );   // 115200 baud
SetupUART( UART_BRR/8 ); // 921600 baud

// Enable GPIOD and GPIOC   
    GPIO_portEnable(GPIO_port_C);
    GPIO_portEnable(GPIO_port_D);
   
while(1)   
    {
       
        uint8_t D5_is_pressed = !GPIO_digitalRead(GPIO_port_D, 3);
        if (D5_is_pressed)
        {
            Delay_Us(0.1);
            uint8_t RW_low = !GPIO_digitalRead(GPIO_port_D, 4);
            if (RW_low)
            {
                uint8_t data2 = GPIOC->INDR;
                printf("%c", data2);
            }
            else if (!RW_low)
            {
                GPIOC->CFGLR = 0b01010101010101010101010101010101;
               
                GPIOC->OUTDR = 255;
                //GPIOC->BSHR =  255;
               
            }
           
        }     
    }
}





 
 

Online brucehoult

  • Super Contributor
  • ***
  • Posts: 4040
  • Country: nz
Sure, you should be able to change the direction of any individual pin (or all of them) at any time. That is integral to any bus-style protocol, even as simple as I2C.

You just have to make sure you are only in output mode when your Chip Enable (derived from address decoding) is selected AND the 6502 is in a read cycle.
 

Offline pancioTopic starter

  • Newbie
  • Posts: 5
  • Country: pl
Hi,

That's I have signal from memory decoder ( /D5) and R/W signal (active low if 6502 writing data on the bus) as mainly condition to read data... and other condition (else if) when processor shall be capable to read data from the databus. I'm not sure that I'm initializing PORTC and sending data in proper way. Any example which I found showing how to change particular bits in the port...   not whole PORT.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5914
  • Country: es
When the pin is set as output you can still read the real value, for example setting the pin high while shorting it to ground would read 0.
You probably want to release the output and read the response from the bus, in that case you must switch between input and output everytime.

Read the GPIO chapter of the reference manual:

http://www.wch-ic.com/downloads/CH32V003RM_PDF.html

You have to modify the CNFy and/or the MODEy bits everytime you want to change the pin mode.

Here:
Code: [Select]
GPIOC->CFGLR = 0b01010101010101010101010101010101
You're doing this:
Code: [Select]

 #    CNFy     MODEy
 0     01       01
 1     01       01
 2     01       01
 3     01       01
 4     01       01
 5     01       01
 6     01       01
 7     01       01

CNFy meaning:
Quote
When in input mode (MODE=00b).
00: Analog input mode.
01: Floating input mode.
10: With pull-up and pull-down mode.
11: Reserved.

In output mode (MODE>00b).
00: Universal push-pull output mode.
01: Universal open-drain output mode.
10: Multiplexed function push-pull output mode.
11: Multiplexing function open-drain output
mode.

MODEy meaning:
Quote
00: Input mode.
01: Output mode, maximum speed 10MHz;
10: Output mode, maximum speed 2MHz.
11: Output mode, maximum speed 50MHz.


So setting CNFy=01 & MODEy=01 means:
CNF 01: Universal open-drain output mode.
MODE 01: Output mode, maximum speed 10MHz.

If you want to set a pin as input you need to set MODEy to 00.
Also I'm not sure it'll work correctly in open drain mode, normally a bus should use push-pull mode (CNFy=0)

To set a pin as input, set CNFy to 01, MODEy to 00.
To set a pin as output, set CNFy to 00, MODEy to 11.

Not hard:
Code: [Select]
// Set any pin as input floating mode or output push-pull mode
void setPinMode(GPIO_TypeDef * GPIOx, uint8_t pin, bool isInput){
  MODIFY_REG(GPIOx->CFGLR, (uint32_t)0x0F<<(pin*4), isInput ? (uint32_t)0x04<<(pin*4) : (uint32_t)0x03<<(pin*4) );
}

void foo(void){
  setPinMode(GPIOC, 1, 1);  // Set PC1 as input
  setPinMode(GPIOC, 1, 0);  // Set PC1 as output
  setPinMode(GPIOA, 6, 1);  // Set PA6 as input
  setPinMode(GPIOB, 4, 0);  // Set PB4 as output
}
« Last Edit: June 19, 2023, 06:28:34 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline pancioTopic starter

  • Newbie
  • Posts: 5
  • Country: pl
Thank you for many details, I tried many options (if something not working you're trying freak methods...:-) )

Code: [Select]
// Reading data directly from PORTC and sending on SERIAL in hex format.
// D3: (D5_is_pressed) chip select
// D4: (RW_low) - Read/Write (active low)

// Could be defined here, or in the processor defines.
#define SYSTEM_CORE_CLOCK 48000000
#define APB_CLOCK SYSTEM_CORE_CLOCK

#include "ch32v003fun.h"
#include <stdio.h>

#include "ch32v003_GPIO_branchless.h"

int main()
{
SystemInit48HSI();
// SetupUART( UART_BRR );   // 115200 baud
SetupUART( UART_BRR/8 ); // 921600 baud

// Enable GPIOD and GPIOC   

    GPIOC->CFGLR = 0b01010101010101010101010101010101;
    //GPIOC->CFGLR = 0b10011001100110011001100110011001;

    GPIO_portEnable(GPIO_port_C);
    GPIO_portEnable(GPIO_port_D);
   
    uint8_t tmp2;
   
while(1)   
    {
       
        uint8_t D5_is_pressed = !GPIO_digitalRead(GPIO_port_D, 3);
        if (D5_is_pressed)
        {
            Delay_Us(0.1);
            uint8_t RW_low = !GPIO_digitalRead(GPIO_port_D, 4);
            if (RW_low)
            {
                uint8_t data2 = GPIOC->INDR;
                //printf("%02x", data2);
                printf("%c", data2);
                tmp2 = data2;
            }
            else
            {
                Delay_Us(0.02);
                GPIOC->CFGLR = 0x11111111; //Universal open-drain output mode, Output mode, maximum speed 10MHz for each pin
                GPIOC->OUTDR = tmp2;
                Delay_Us(0.2);
                //GPIOC->BSHR =  0xff;
                GPIOC->CFGLR = 0x44444444;  //default value 0b0100 for each pin
                Delay_Us(0.2);
               
            }
         
        }     
    }
}


Finally I read the RM but I'm still not sure when I should use OUTDR.. instead BSHR etc.  The code above working.. but sometimes 6502 going to hell... This is tweaking of time conditions process and most often failed... I'm afraid, 48MHz is not to enough for V003 program to operate with bus (1.77Mhz) 6502 like sequential machine. Maybe some assembler part will be necessary.

There is one another pin available on the 6502 bus called PHI2 - it's clock ticking with 1.77MHz - I'm considering to use it as synchro if the frequency will be not so high for V003.

There is schematic which will be adapted:





 
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5914
  • Country: es
OUTDR writes to the Port directly, BSHR directly sets or resets a pin by writing a 1 into the correct place.

BSHR is better for single pin changes as you don't have to read the port value first, modify (mask) to preserve the rest and write back.
Just write a 1 somewhere, pin x of Port y will (re)set

If you want to load an entire byte like 0x35, overwriting the entire port, OUTDR is the way to go, this is what you would use with PortC, sending a whole byte to the bus.

It's going to hell due the printf calls you use, they're stalling your code flow.

Your code is misleading:
Code: [Select]
uint8_t D5_is_pressed = !GPIO_digitalRead(GPIO_port_D, 3);   // but PD3 is A3 ?
uint8_t RW_low = !GPIO_digitalRead(GPIO_port_D, 4);   // But PD4 is CS0 ?

Not sure, but it seems to me you must use better timing accuracy.
Instead delay_us(0.2) try inserting few NOPs, they waste one CPU clock so 20.8ns, so try:
Code: [Select]
// 10 NOPs, 208ns
asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop”);
20.8ns is the lowest delay you can get, or multiples of it.

Ensure to properly check the 6502 bus timings, 200ns seems too small for a bus running at 1.77MHz (282ns seems like it?) but I have no idea about it so it could be correct.
« Last Edit: June 20, 2023, 10:05:37 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline pancioTopic starter

  • Newbie
  • Posts: 5
  • Country: pl
Thanks for new information. At first I shall to explain - attached schematic is related to future device. The presented code is just only proof of concept "how to connect V003 to 6502 data bus". So, I used R/W and decoded $D5XX signal from address bus to check that V003 is capable to communicate/cooperate with 6502 without any interference. So don't correlate code with hardware example, please (my fault! I forgot notice this fact) :-)

Ok, let's return to discussion... I can imagine that printf() can be so slowly... the best metod will be send data directly to SERIAL using proper registers - at this moment I don't know how to do it. But.... I thought, if V003 is capable to receive each data from 6502's data bus correctly without any holes then print these on serial, take another one byte form bus etc... it means that V003 have enough time. Am I wrong?.

Regarding time accuracy... that's I missed - the part of asm. I tried to use DelayMs(), DelayUs() and DelaySysTick() thinking that compiler will do proper calculation for me... Am I wrong again? So, I'll try to check time conditions physically by using digital analyzer...
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5914
  • Country: es
Still, sending data using the serial port will be a lot slower than a 1.7MHz bus.
The only solution coming to my mind would be to implement a non-blocking function using dma, but will overload anyways if there's too much bus activity.
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline pancioTopic starter

  • Newbie
  • Posts: 5
  • Country: pl
I agree but how to explain fact that each byte sending by Atari's CPU is received and sending to serial without lost any one? I changed serial speed to 921600 baud. We should realize, that not any 6502 CPU tick finished with sending proper (expected) data to databus. I need to calculate but I suppose it takes about 30-50 1.77MHz's ticks... Let me do some tests...



So.... ~150KB in 10s == 15KB/s not bad...




 
« Last Edit: June 20, 2023, 11:12:38 am by pancio »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf