- Tue Aug 16, 2016 11:11 pm
A few things, that I think explain most of what's going on here:
* GPIOs hang off a peripheral bus (APB I'm fairly sure). Peripheral bus is slower than the CPU, I'm fairly sure default speed is half the standard CPU speed so 40MHz. Even when CPU speed is doubled to 160MHz, this bus stays at 40MHz (the doubling only effects CPU clock). So 17 CPU cycles @ 160MHz is 4 peripheral bus cycles, plus 1 CPU cycle.
* From what you're reporting, writes seem to take ~13 CPU cycles @ 160MHz. So one peripheral bus cycle less than reads. There might be a way to equalise this timing for reads (maybe by reading a different register), but it's probably a hardware limitation.
* More serious is the problem where the CPU stalls on a read until it's complete. Unfortunately I'm 99% sure this is a CPU design limitation. LX106 CPU has a single entry write buffer (you see this option mentioned in the Xtensa ISA manual, and the lx106-hal contains "XCHAL_NUM_WRITEBUFFER_ENTRIES 1"). This means that a write is buffered by the CPU, so it can do other things until the write completes. This is why you get 12 extra CPU cycles when you write to a GPIO register, the write buffer is handling this write and the CPU can do anything else which doesn't also trigger a bus write.
(BTW, this buffering is also one of the use cases for the MEMW instruction - when you need to know that writes are actually complete before you can continue.)
* The bad news is, there is no equivalent "read buffer" in LX106 - if you read from memory, the CPU doesn't continue until the read is complete. This is why you're seeing 17 cycles to complete a load.
I don't know of a way around this. I think it's the kind of use case (bit-banging GPIO reads at >10MHz) that noone really thought would exist, so it's not been designed for. The design of the CPU considers that it's more important that registers have read correct values before the CPU executes the next instruction. Sorry!
When I get a chance I will double-check you can't clock the GPIO's bus any higher, but I'm 99% sure this isn't possible (and even if it is possible, doing it will probably break other peripherals.)