[CH32V003] The easiest way to use port C/D as INPUT and OUTPUT in the same time? - Page 1
Forum section: electronics / general

author: pancio
author_rank: Contributor
timestamp: June 19, 2023, 07:22:03 am
content: 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:// 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 baudSetupUART( UART_BRR/8 ); // 921600 baud// Enable GPIOD and GPIOCGPIO_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;}}}}

author: brucehoult
author_rank: Super Contributor
timestamp: June 19, 2023, 09:44:07 am
content: 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.

author: pancio
author_rank: Contributor
timestamp: June 19, 2023, 04:02:56 pm
content: 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.

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 19, 2023, 06:06:59 pm
content: 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.htmlYou have to modify the CNFy and/or the MODEy bits everytime you want to change the pin mode.Here:Code:GPIOC->CFGLR = 0b01010101010101010101010101010101You're doing this:Code:# CNFy MODEy0 01 011 01 012 01 013 01 014 01 015 01 016 01 017 01 01CNFy meaning:QuoteMODEy meaning:QuoteSo 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:// Set any pin as input floating mode or output push-pull modevoid 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 inputsetPinMode(GPIOC, 1, 0); // Set PC1 as outputsetPinMode(GPIOA, 6, 1); // Set PA6 as inputsetPinMode(GPIOB, 4, 0); // Set PB4 as output}

author: pancio
author_rank: Contributor
timestamp: June 19, 2023, 07:31:31 pm
content: Thank you for many details, I tried many options (if something not working you're trying freak methods...:-) )Code:// 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 baudSetupUART( UART_BRR/8 ); // 921600 baud// Enable GPIOD and GPIOCGPIOC->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 pinGPIOC->OUTDR = tmp2;Delay_Us(0.2);//GPIOC->BSHR = 0xff;GPIOC->CFGLR = 0x44444444; //default value 0b0100 for each pinDelay_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:

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 19, 2023, 11:31:18 pm
content: 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)setIf 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: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:// 10 NOPs, 208nsasm("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.

author: pancio
author_rank: Contributor
timestamp: June 20, 2023, 09:34:14 am
content: 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...

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 20, 2023, 10:10:40 am
content: 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.

author: pancio
author_rank: Contributor
timestamp: June 20, 2023, 10:22:39 am
content: 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...