Introduction
For STM, the common ways to manipulate low hardware are HAL and memory/register access. For third-party hardwares, there are no HAL support and we have to do memory/register access. For example, for ili9341 TFT LCD, the driving code looks like the following:
// Define the memory model for IO/Register access.
typedef struct {
__IO uint16_t reg;
__IO uint16_t mem;
} LCD_TypeDef;
#define LCD_BASE ((uint32_t)(0x6C000000 | 0x000007FE))
#define LCD ((LCD_TypeDef *)LCD_BASE)
// Write commands by assignment.
// NOTE: If people know some about FPGA will
// figure out that they are much similar.
INLINE void lcd_cmd(uint16_t cmd) {LCD->reg = cmd;}
// Write data by assignment.
INLINE void lcd_data(uint16_t dat) {LCD->mem = dat;}
INLINE void lcd_cmd_data(uint16_t cmd, uint16_t data) {
LCD->reg = cmd;
LCD->mem = data;
}
Personally, I prefer to C++. So the C++ style code will be:
#include <stm32f1xx.h>
namespace igame {
template<typename T, const uint32_t ADDR>
struct IOMemory {
typedef IOMemory<T, ADDR> type;
typedef T val_t;
typedef const T const_val_t;
__IO T* __mem = reinterpret_cast<val_t *>(ADDR);
};
// Input
template<typename T, const uint32_t ADDR>
void operator << (IOMemory<T, ADDR>& left, const uint16_t& right) {*left.__mem = right;}
// Output
template<typename T, const uint32_t ADDR>
void operator << (const IOMemory<T, ADDR>& left, const int& right) {left << (const uint16_t&)right;
}
template<typename T, const uint32_t ADDR>
void operator >> (const IOMemory<T, ADDR>& left, T& right) {right = *left.__mem;}
} // ns
The working code should be:
namespace igame {
class TFT9341 {
...
private:
static const uint32_t LCD_BASE_ADDR = ((uint32_t) (0x6C000000 | 0x000007FE));
const IOMemory<uint16_t, LCD_BASE_ADDR> m_reg;
const IOMemory<uint16_t, LCD_BASE_ADDR + sizeof(uint16_t)> m_mem;
...
public:
...
uint16_t getId() {
uint16_t res = 0;
m_reg >> res;
if (res < 0xFF || res == 0xFFFF || res == 0x9300) {
m_reg << 0xD3; // Write cmd.
m_mem >> res; // Output: 0x00
m_mem >> res; // Output: 0x00
m_mem >> res; // Output: 0x93
uint16_t temp = res << 8;
m_mem >> res; // Output: 0x41
res |= temp;
}
return res;
} // fn getId()
void setPos(uint16_t x, uint16_t y) {
m_reg << 0x2A;
m_mem << (x >> 8);
m_mem << (x & 0xFF);
m_reg << 0x2B;
m_mem << (y >> 8);
m_mem << (y & 0xFF);
} // fn setPos
...
}; // class
} // ns