Closed acristoffers closed 6 years ago
Hm, I've stepped through
GpioPort<GpioB6, 4, xpcc::GpioPort::DataOrder::Reversed>::write(0b0011)
on a STM32F072 but I can't find the problem:
StartPinReversed = StartPin = 6
(correct).portMask
is 0x3c0 = 0b0000'0011'1100'0000
(correct).xpcc::bitReverse(0x0c0 = 0b0000'0000'1100'0000)
returns 0x300 = 0b0000'0011'0000'0000
(correct).GPIOB->ODR
is read as 0
(for me), and written back as 0x300
(correct).Can you try out the SoftwareGpioPort
, so make sure your hardware setup etc is correct?
using Data = xpcc::SoftwareGpioPort<GpioB6, GpioB7, GpioB8, GpioB9>; // bit3, bit2, bit1, bit0
If in your debugger you can read p/x GPIOB-ODR
and confirm that the correct bits are actually set high after a Data::write()
, but they still don't show up on the physical bus, the lines may be shorted to ground for some reason. In that case SoftwareGpioPort
won't help either.
I'll try the SoftwareGpioPort
. The difference between ours tests is on line 3, mine returns 0x30, not 0x300.
Oh, and there are no physical problems. I can drive it by driving the lines myself using set()
and reset()
.
If I use SoftwareGpioPort and tell it to write 0x30 it will write 0, because it will use the lower nibble, not the high one.
data & (1 << (width-1))
<= width is 4->3->2->1, so the mask is 0b1000, 0b0100, 0b0010, 0b0001.
Shouldn't this function be shifting the high nibble into the low one to get written?
xpcc::Hd44780Base<DATA, RW, RS, E>::Bus<Data, Enable, 4>::writeHighNibble(uint8_t data)
{
Bus<DATA, E, 8>::write(data);
}
Because it's only calling write on a Bus with 8 bits, but
xpcc::Hd44780Base<DATA, RW, RS, E>::Bus<Data, Enable, 8>::write(uint8_t data)
{
DATA::setOutput();
DATA::write(data);
E::set();
xpcc::delayMicroseconds(1);
E::reset();
}
this function is just writing using DATA, wich is 4 bits and will take only the lower bits.
Changing
xpcc::Hd44780Base<DATA, RW, RS, E>::Bus<Data, Enable, 4>::writeHighNibble(uint8_t data)
{
Bus<DATA, E, 8>::write(data);
}
to
xpcc::Hd44780Base<DATA, RW, RS, E>::Bus<Data, Enable, 4>::writeHighNibble(uint8_t data)
{
Bus<DATA, E, 8>::write(data >> 4);
}
makes it work with SoftwareGpioPort
.
Good catch! Do you want to create a PR?
I'll investigate a bit more. My display is not going into 2 lines mode and it still doesn't seem to work with GpioPort
. I'll see if I can find what's wrong with that.
Ok, for testing reference: I tested this driver only with a 40x4 dual display, using the xpcc::Hd44780Dual
class, both with 8-bit and 4-bit busses.
However, in this example @strongly-typed tested a 20x4 display over an I2C expander on STM32F4.
I think I remember him complaining about some bugs too, but I don't remember if he solved them in the end.
Something is happening: if I use the Data type directly, it does not update the µC output, even through GPIOB->ODR is set correctly. If before using I do
GpioB6::setOutput();
GpioB7::setOutput();
GpioB8::setOutput();
GpioB9::setOutput();
then it works as expected. However, it seems to me that both GpioPort::setOutput() and GpioB*::setOutput() do the same thing.
Ah, there is a bug here: The GPIOx->MODER
register has 2bit wide entries per GPIO, but the portMask2
has the right width, but the wrong offset.
This
static constexpr uint32_t portMask2 = portMask | (portMask << Width);
ought to be
static constexpr uint32_t portMask2 = (portMask | (uint32_t(portMask) << Width)) << StartPin;
In your example the portMask2
is 0x3fc0
, which starts at bit 6 with a width of 8 bits. This then configures B3, B4, B5, B6 as output, which is incorrect. It is supposed to be 0xff000
.
Who the heck writes such terrible code? *git blame* Oh it was me…
We need better hardware testing, we need hwut, (paging @strongly-typed).
Made a pull request (#326) for the byte shiffting problem. Still can't figure out why it doesn't go to 2 lines mode by itself. If I send the command after initialize()
it works.
~Hm, are you waiting 50ms before calling initialize()
? The display executes its reset instructions during this time (datasheet says 10ms of busy time).~ (meh, but only after a power reset, likely not the case here).
Do the above changes fix your GpioPort
issues?
Yes, that change fixes it. And I wait 100ms. Duplicating the command works, even if the duplication is inside the initialize function (just calling twice in row).
Hi. I tried to use the Hd44780 class with a 16x2 display, single driver, 4 bit databus. The display is connected as such:
To use the class, I created a bus starting at
GpioB6
, with width=4 and reversed. The Display library commands are being mostly wiped out by the functionGpioPortBase::write(uint16_t data)
.While debugging, when I get to this function I have the right value in the data variable. However, after the line
the data is not on the right place, so it gets wiped out by the mask (
data & portMask
).The function
xpcc::Hd44780Base<DATA, RW, RS, E>::initialize(LineMode lineMode)
in the filehd44780_base_impl.hpp
should write 0011 in the bus (B6, B7, B8, B9) when it callsBus<DATA, E, DATA::width>::writeHighNibble(Set8BitBus);
. But whenGPIOB->ODR = (GPIOB->ODR & ~portMask) | (data & portMask);
gets called, the output on the bus is 0000;How I do the setup: