Fix LCD timings

Fixes some noise on a few sensitive panels

Change-Id: Ie6117a629455e1d487a8dd824fd8b73529c90e5f
This commit is contained in:
Romain Goyet
2017-06-29 11:26:13 +02:00
parent 602647a0c6
commit 4c3e62e6a5
2 changed files with 68 additions and 57 deletions

View File

@@ -164,67 +164,60 @@ void shutdownGPIO() {
}
void initFSMC() {
// Control register
FSMC.BCR(FSMCMemoryBank)->setMWID(FSMC::BCR::MWID::SIXTEEN_BITS);
FSMC.BCR(FSMCMemoryBank)->setWREN(true);
FSMC.BCR(FSMCMemoryBank)->setMBKEN(true);
/* Set up the FSMC control registers.
* We address the LCD panel as if it were an SRAM module, using a 16bits wide
* bus, non-multiplexed.
* The STM32 FSMC supports two kinds of memory access modes :
* - Base modes (1 and 2), which use the same timings for reads and writes
* - Extended modes (named A to D), which can be customized further.
* The LCD panel can be written to faster than it can be read from, therefore
* we want to use one of the extended modes. */
FSMC.BCR(FSMCMemoryBank)->setEXTMOD(true);
FSMC.BCR(FSMCMemoryBank)->setWREN(true);
FSMC.BCR(FSMCMemoryBank)->setMWID(FSMC::BCR::MWID::SIXTEEN_BITS);
FSMC.BCR(FSMCMemoryBank)->setMTYP(FSMC::BCR::MTYP::SRAM);
FSMC.BCR(FSMCMemoryBank)->setMUXEN(false);
FSMC.BCR(FSMCMemoryBank)->setMBKEN(true);
/* From AN2790 Application note - TFT LCD interfacing with the high-density
* STM32F10xxx FSMC and STM32F412 reference manual:
* (ADDSET + DATAST) × HCLK = Tcyc(Read cycle time)
* DATAST × HCLK = Twrlr (Low pulse width for read)
* DATAST = (((Tacc(Data access time) + Tas(Address setup time)) +
* (tsu(Data_NE)+ tv(A_NE)))/HCLK) ADDSET 4
* With:
* tsu(Data_NE): FSMC_NEx low to data valid
* tv(A_NE): FSMC_NEx low to FSMC_A valid
/* We now need to set the actual timings. First, the FSMC and LCD specs don't
* use the same names. Here's the mapping:
*
* Hence:
* T(HCLK) = 1*10^(9)/(96MHz*10^6) = 10.42 ns (Cf STM32F412 datasheet)
* tsu(Data_NE) = T(HCLK) - 1 = 9.42 ns (Cf STM32F412 datasheet)
* tv(A_NE) = 1.5 ns (Cf STM32F412 datasheet)
* Tcyc(read) = 450 ns (Cf ST7789 datasheet)
* Twrlr = 45 ns (Cf ST7789 datasheet)
* Tacc(read) = 340 ns (Cf ST7789 datasheet)
* Tas = 0 ns (Cf ST7789 datasheet)
* FSMC | LCD
* -----+-----
* NOE | RDX
* NWE | WRX
* NE1 | CSX
* A16 | D/CX
* Dn | Dn
*
* ADDSET(read) = 29
* DATAST(read) = 5*/
* We need to set the values of the BTR and BWTR which gives the timings for
* reading and writing. Note that the STM32 datasheet doesn't take into
* account the time needed to actually switch from one logic state to another,
* whereas the ST7789V one does, so we'll add T(R) and T(F) as needed.
* Last but not least, timings on the STM32 have to be expressed in terms of
* HCLK = 1/96MHz = 10.42ns.
* - We'll pick Mode A which corresponds to SRAM with OE toggling
* - ADDSET = T(AST) + T(F) = 0ns + 15ns = 2 HCLK
* - ADDHLD is unused in this mode, set to 0
* - DATAST(read) = T(RDLFM) + T(R) = 355ns + 15ns = 36 HCLK
* DATAST(write) = T(WRL) + T(R) = 15ns + 15ns = 3 HCLK
* - BUSTURN(read) = T(RDHFM) + T(F) = 90ns + 15ns = 10 HCLK
* BUSTURN(write) = T(RDHFM) + T(F) = 15ns + 15ns = 3 HCLK
*/
// Reading timing register
FSMC.BTR(FSMCMemoryBank)->setADDSET(29);
FSMC.BTR(FSMCMemoryBank)->setDATAST(5);
FSMC.BTR(FSMCMemoryBank)->setBUSTURN(0);
FSMC.BTR(FSMCMemoryBank)->setACCMOD(1);
// Read timing from the LCD
FSMC.BTR(FSMCMemoryBank)->setADDSET(2);
FSMC.BTR(FSMCMemoryBank)->setADDHLD(0);
FSMC.BTR(FSMCMemoryBank)->setDATAST(36);
FSMC.BTR(FSMCMemoryBank)->setBUSTURN(10);
FSMC.BTR(FSMCMemoryBank)->setACCMOD(FSMC::BTR::ACCMOD::A);
/* From AN2790 Application note - TFT LCD interfacing with the high-density
* STM32F10xxx FSMC and STM32F412 reference manual:
* (ADDSET+ (DATAST + 1)) × HCLK = Tcyc(Write or read cycle time)
* DATAST × HCLK = Twrlw (Low pulse width for write)
* DATAST = (((Tacc(Data access time) + Tas(Address setup time)) +
* (tsu(Data_NE)+ tv(A_NE)))/HCLK) ADDSET 4
* With:
* tsu(Data_NE): FSMC_NEx low to data valid
* tv(A_NE): FSMC_NEx low to FSMC_A valid
*
* Hence:
* T(HCLK) = 1*10^(9)/(96MHz*10^6) = 10.42 ns (Cf STM32F412 datasheet)
* tsu(Data_NE) = T(HCLK) - 1 = 9.42 ns (Cf STM32F412 datasheet)
* tv(A_NE) = 1.5 ns (Cf STM32F412 datasheet)
* Tcyc(write) = 66 ns (Cf ST7789 datasheet)
* Twrlw = 15 ns (Cf ST7789 datasheet)
* Tacc(write) = 80 ns ?
* Tas = 0 ns (Cf ST7789 datasheet)
*
* ADDSET(write) = 4
* DATAST(write) = 2 */
// Writing timing register
FSMC.BWTR(FSMCMemoryBank)->setADDSET(4);
FSMC.BWTR(FSMCMemoryBank)->setDATAST(2);
FSMC.BWTR(FSMCMemoryBank)->setBUSTURN(0);
FSMC.BTR(FSMCMemoryBank)->setACCMOD(1);
// Write timings for the LCD
FSMC.BWTR(FSMCMemoryBank)->setADDSET(2);
FSMC.BWTR(FSMCMemoryBank)->setADDHLD(0);
FSMC.BWTR(FSMCMemoryBank)->setDATAST(3);
FSMC.BWTR(FSMCMemoryBank)->setBUSTURN(3);
FSMC.BWTR(FSMCMemoryBank)->setACCMOD(FSMC::BWTR::ACCMOD::A);
}
void shutdownFSMC() {

View File

@@ -7,12 +7,18 @@ class FSMC {
public:
class BCR : Register32 {
public:
enum class MTYP : uint8_t {
SRAM = 0,
PSRAM = 1,
NOR = 2
};
enum class MWID : uint8_t {
EIGHT_BITS = 0,
SIXTEEN_BITS = 1
};
REGS_BOOL_FIELD(MBKEN, 0);
REGS_BOOL_FIELD(MUXEN, 1);
REGS_TYPE_FIELD(MTYP, 3, 2);
REGS_TYPE_FIELD(MWID, 5, 4);
REGS_BOOL_FIELD(WREN, 12);
REGS_BOOL_FIELD(EXTMOD, 14);
@@ -20,24 +26,36 @@ public:
class BTR : Register32 {
public:
enum class ACCMOD : uint8_t {
A = 0,
B = 1,
C = 2,
D = 3
};
REGS_FIELD(ADDSET, uint8_t, 3, 0);
REGS_FIELD(ADDHLD, uint8_t, 7, 4);
REGS_FIELD(DATAST, uint8_t, 15, 8);
REGS_FIELD(BUSTURN, uint8_t, 19, 16);
REGS_FIELD(CLKDIV, uint8_t, 23, 20);
REGS_FIELD(DATLAT, uint8_t, 27, 24);
REGS_FIELD(ACCMOD, uint8_t, 29, 28);
REGS_TYPE_FIELD(ACCMOD, 29, 28);
};
class BWTR : Register32 {
public:
enum class ACCMOD : uint8_t {
A = 0,
B = 1,
C = 2,
D = 3
};
REGS_FIELD(ADDSET, uint8_t, 3, 0);
REGS_FIELD(ADDHLD, uint8_t, 7, 4);
REGS_FIELD(DATAST, uint8_t, 15, 8);
REGS_FIELD(BUSTURN, uint8_t, 19, 16);
REGS_FIELD(CLKDIV, uint8_t, 23, 20);
REGS_FIELD(DATLAT, uint8_t, 27, 24);
REGS_FIELD(ACCMOD, uint8_t, 29, 28);
REGS_TYPE_FIELD(ACCMOD, 29, 28);
};
constexpr FSMC() {}