or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

character-displays.mdcolor-displays.mdgreyscale-displays.mdindex.mdinterfaces.mdmonochrome-displays.md

character-displays.mddocs/

0

# Character/Text Displays

1

2

Text-oriented OLED displays that support both graphical rendering and character-based text display with embedded fonts. These displays combine the flexibility of graphics with the convenience of character addressing.

3

4

## Capabilities

5

6

### WS0010 Display

7

8

Serial interface to a monochrome Winstar WS0010 OLED display with character support, embedded fonts, and both graphical and text modes.

9

10

```python { .api }

11

class ws0010:

12

def __init__(self, serial_interface=None, width=100, height=16, undefined='_', font=None, selected_font=0, exec_time=1e-6 * 50, rotate=0, framebuffer=None, **kwargs):

13

"""

14

Initialize WS0010 OLED character display.

15

16

Parameters:

17

- serial_interface: Parallel interface (luma.core.interface.serial.parallel)

18

- width: Number of horizontal pixels (default: 100)

19

- height: Number of vertical pixels (default: 16)

20

- undefined: Character to display for missing glyphs (default: '_')

21

- font: Override internal font with PIL.ImageFont (optional)

22

- selected_font: Select embedded font table by name/number (default: 0)

23

- exec_time: Command execution time in seconds (default: 50µs)

24

- rotate: Rotation value 0-3 (0°, 90°, 180°, 270°) (default: 0)

25

- framebuffer: Framebuffering strategy (diff_to_previous or full_frame)

26

"""

27

28

def display(self, image):

29

"""

30

Display a 1-bit PIL Image on the WS0010 OLED.

31

32

Parameters:

33

- image: PIL.Image in mode "1" (1-bit monochrome)

34

"""

35

36

def get_font(self, ft):

37

"""

38

Load embedded font by index or name.

39

40

Parameters:

41

- ft: Font index (int) or name (str)

42

43

Returns:

44

Font object for the specified embedded font

45

"""

46

47

@property

48

def text(self) -> str:

49

"""Get the current text content displayed on screen."""

50

51

@text.setter

52

def text(self, value: str):

53

"""

54

Set text content to display on screen.

55

56

Parameters:

57

- value: Text string to display, supports newlines

58

"""

59

```

60

61

**Supported Resolutions**: (40,8), (40,16), (60,8), (60,16), (80,8), (80,16), (100,8), (100,16)

62

63

**Available Embedded Fonts**:

64

65

| Number | Name | Font | Size |

66

|--------|----------|----------------------|------|

67

| 0 | FT00 | English Japanese | 5x8 |

68

| 1 | FT01 | Western European I | 5x8 |

69

| 2 | FT10 | English Russian | 5x8 |

70

| 3 | FT11 | Western European II | 5x8 |

71

| 4 | FT00_10 | English Japanese | 5x10 |

72

| 5 | FT01_10 | Western European I | 5x10 |

73

| 6 | FT10_10 | English Russian | 5x10 |

74

| 7 | FT11_10 | Western European II | 5x10 |

75

76

Usage example:

77

78

```python

79

from luma.core.interface.serial import parallel

80

from luma.oled.device import ws0010

81

82

# Initialize with parallel interface

83

serial = parallel(RS=7, E=8, PINS=[25, 24, 23, 18])

84

device = ws0010(serial, width=100, height=16, selected_font='FT01')

85

86

# Display text using character interface

87

device.text = "WS0010 Display\nLine 2 Text"

88

89

# Or use graphical interface

90

with canvas(device) as draw:

91

draw.text((0, 0), "Graphics Mode", fill="white")

92

draw.rectangle((0, 8, 100, 16), outline="white")

93

94

# Load and use different fonts

95

font = device.get_font('FT11') # Western European II

96

device.text = "Çafé naïve résumé"

97

```

98

99

### Winstar WEH Display

100

101

Character-based Winstar WEH OLED display using the WS0010 controller with grid-optimized font rendering.

102

103

```python { .api }

104

class winstar_weh(ws0010):

105

def __init__(self, serial_interface=None, width=16, height=2, **kwargs):

106

"""

107

Initialize Winstar WEH character OLED display.

108

109

Parameters:

110

- serial_interface: Parallel interface (luma.core.interface.serial.parallel)

111

- width: Number of characters per line (default: 16)

112

- height: Number of lines (default: 2)

113

- undefined: Character to display for missing glyphs (default: '_')

114

- font: Override internal font with PIL.ImageFont (optional)

115

- default_table: Select embedded font table (optional)

116

- embedded_font: Select font size "5x8" or "5x10" (default: "5x8")

117

- exec_time: Command execution time in seconds (default: 50µs)

118

- rotate: Rotation value 0-3 (0°, 90°, 180°, 270°) (default: 0)

119

- framebuffer: Framebuffering strategy (diff_to_previous or full_frame)

120

121

Note: Width/height specified in characters, not pixels.

122

Internal pixel dimensions are width*5 x height*8.

123

"""

124

```

125

126

Usage example:

127

128

```python

129

from luma.core.interface.serial import parallel

130

from luma.oled.device import winstar_weh

131

132

# Initialize 16x2 character display

133

serial = parallel(RS=7, E=8, PINS=[25, 24, 23, 18])

134

device = winstar_weh(serial, width=16, height=2)

135

136

# Display character-based text

137

device.text = "Line 1 Text\nLine 2 Text"

138

139

# Text automatically wraps at character boundaries

140

device.text = "This is a long line of text that will wrap"

141

```

142

143

## Character vs Graphical Modes

144

145

### Character Mode

146

147

Character mode uses the text property for simple text display:

148

149

```python

150

# Character mode - automatic font rendering

151

device.text = "Hello World!\nSecond Line"

152

153

# Supports basic formatting

154

device.text = "Temperature: 23°C\nHumidity: 65%"

155

156

# Unicode characters (if font supports them)

157

device.text = "Café naïve résumé"

158

```

159

160

### Graphical Mode

161

162

Graphical mode provides full drawing capabilities:

163

164

```python

165

# Graphical mode - full PIL drawing

166

with canvas(device) as draw:

167

draw.text((0, 0), "Custom Graphics", fill="white")

168

draw.line([(0, 8), (100, 8)], fill="white")

169

draw.rectangle((10, 10, 90, 15), outline="white")

170

draw.point([(5, 5), (95, 5)], fill="white")

171

```

172

173

## Font Management

174

175

### Using Embedded Fonts

176

177

```python

178

# Select font during initialization

179

device = ws0010(serial, selected_font='FT01') # Western European

180

181

# Or load font dynamically

182

font_obj = device.get_font(2) # English Russian (FT10)

183

184

# Access font by name or number

185

font1 = device.get_font('FT11_10') # 5x10 Western European II

186

font2 = device.get_font(7) # Same font by number

187

```

188

189

### Custom Fonts

190

191

```python

192

from PIL import ImageFont

193

194

# Use custom PIL font instead of embedded fonts

195

custom_font = ImageFont.load("custom.pil")

196

device = ws0010(serial, font=custom_font)

197

198

# Embedded fonts are bypassed when custom font is provided

199

device.text = "Custom Font Text"

200

```

201

202

## Interface Configuration

203

204

Character displays typically use parallel interfaces:

205

206

```python

207

from luma.core.interface.serial import parallel

208

209

# Standard parallel configuration

210

serial = parallel(

211

RS=7, # Register Select pin

212

E=8, # Enable pin

213

PINS=[25, 24, 23, 18] # Data pins (D4-D7 for 4-bit mode)

214

)

215

216

# 8-bit mode (if supported)

217

serial = parallel(

218

RS=7, E=8,

219

PINS=[25, 24, 23, 18, 17, 16, 15, 14] # D0-D7 for 8-bit mode

220

)

221

```

222

223

## Common Patterns

224

225

### Error Handling

226

227

```python

228

import luma.core.error

229

230

try:

231

device = ws0010(serial, width=200, height=200)

232

except luma.core.error.DeviceDisplayModeError as e:

233

print(f"Unsupported display mode: {e}")

234

```

235

236

### Display Initialization

237

238

Character displays have longer initialization times:

239

240

```python

241

from time import sleep

242

243

# Initialize device

244

device = ws0010(serial)

245

246

# Device automatically sleeps 0.5s during initialization

247

# Additional delays may be needed for complex setups

248

sleep(0.1)

249

250

device.text = "Ready!"

251

```

252

253

### Grid Considerations for WEH Displays

254

255

WEH displays have 1-pixel gaps every 5th column:

256

257

```python

258

# WEH displays have grid structure

259

device = winstar_weh(serial, width=16, height=2)

260

261

# Text interface automatically handles grid

262

device.text = "Grid Aligned"

263

264

# For graphics, be aware of grid gaps

265

with canvas(device) as draw:

266

# Gaps occur at x = 5, 10, 15, 20, etc.

267

draw.text((0, 0), "Account for gaps in graphics")

268

```

269

270

### Performance Tips

271

272

```python

273

# Use appropriate framebuffer for usage pattern

274

from luma.core.framebuffer import diff_to_previous, full_frame

275

276

# For frequently changing text

277

device = ws0010(serial, framebuffer=diff_to_previous())

278

279

# For static or infrequent updates

280

device = ws0010(serial, framebuffer=full_frame())

281

282

# Reset display if needed (4-bit mode only)

283

# Device automatically resets when in 4-bit mode for synchronization

284

```