Skip to content

Commit ccc7d20

Browse files
Add files via upload
Initial ipload
1 parent 1e6e3c7 commit ccc7d20

28 files changed

+3843
-0
lines changed

VGA/VGA_800x600.py

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.

VGA/VGA_fonts.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Font library reused from the xglcd font library by rdagger
2+
# https://github.com/rdagger/micropython-ili9341/tree/master
3+
4+
class Font:
5+
"""Font data in X-GLCD format.
6+
7+
Attributes:
8+
letters: A bytearray of letters (columns consist of bytes)
9+
font_width: Maximum pixel width of font
10+
font_height: Pixel height of font
11+
start_letter: ASCII number of first letter
12+
bytes_per_letter: How many bytes in one letter
13+
14+
Note:
15+
Font files can be generated with the free version of MikroElektronika
16+
GLCD Font Creator: www.mikroe.com/glcd-font-creator
17+
The font file must be in X-GLCD 'C' format.
18+
To save text files from this font creator program in Win7 or higher
19+
you must use XP compatibility mode or you can just use the clipboard.
20+
"""
21+
22+
def __init__(self, path, width, height, start_letter=32, letter_count=96, char_spacing=1, line_spacing=2):
23+
"""Constructor for X-GLCD Font object.
24+
25+
Args:
26+
path (string): Full path of font file
27+
width (int): Maximum width in pixels of each letter
28+
height (int): Height in pixels of each letter
29+
start_letter (int): First ASCII letter. Default is 32.
30+
letter_count (int): Total number of letters. Default is 96.
31+
char_spacing (int) pixels between char when pronting multiple chars
32+
line_spacing (int) pixels between lines when line feed
33+
"""
34+
self.width = width
35+
self.height = max(height, 8)
36+
self.start_letter = start_letter
37+
self.letter_count = letter_count
38+
self.bytes_per_letter = (int(
39+
(self.height - 1) / 8) + 1) * self.width + 1
40+
self.load_xglcd_font(path)
41+
self.char_spacing = char_spacing
42+
self.line_spacing = line_spacing
43+
44+
def load_xglcd_font(self,font_filename):
45+
print(font_filename)
46+
self.letters = bytearray(self.bytes_per_letter * self.letter_count)
47+
offset=0
48+
with open(font_filename, 'r') as f:
49+
for line in f:
50+
# Skip lines that do not start with hex values
51+
line = line.strip()
52+
if len(line) == 0 or line[0:2] != '0x':
53+
continue
54+
# Remove comments
55+
comment = line.find('//')
56+
if comment != -1:
57+
line = line[0:comment].strip()
58+
# Remove trailing commas
59+
if line.endswith(','):
60+
line = line[0:len(line) - 1]
61+
# Convert hex strings to bytearray and insert in to letters
62+
self.letters[offset: offset + self.bytes_per_letter] = bytearray(
63+
int(b, 16) for b in line.split(','))
64+
offset += self.bytes_per_letter
65+
66+
def Get_letter(self,char):
67+
init_index=(ord(char)-self.start_letter)*self.bytes_per_letter
68+
letter=self.letters[init_index:init_index+self.bytes_per_letter]
69+
return(letter)

VGA/VGA_plot.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# VGA simple plotter by Hugh - May 2025
2+
from VGA.VGA_fonts import Font
3+
4+
# 3 bit color names
5+
RED = 0b001
6+
GREEN = 0b010
7+
BLUE = 0b100
8+
YELLOW = 0b011
9+
BLACK = 0
10+
WHITE = 0b111
11+
CYAN = 0b110
12+
MAGENTA = 0b101
13+
14+
15+
class Plot:
16+
"""A two dimensionnal plot object for the VGA 800x600 display.
17+
18+
Note: All coordinates are zero based.
19+
"""
20+
21+
def __init__(self, display, ul_x=1, ul_y=1, br_x=400, br_y=300,ax_color=WHITE, min_x=0,\
22+
max_x=100, min_y=0, max_y=100, x_ticks_num=10,y_ticks_num=10):
23+
"""Initialize plot.
24+
25+
Args:
26+
display : the VGA screen object
27+
ul_x,y : upper left coordinates of the rectangle plotting area (including ticks)
28+
br_x,y : bottom righy coordinates of the rectangle plotting area (including ticks)
29+
ax_color : color of the axes and ticks
30+
plot_color : color of the plot
31+
min_max_x_y : min/max values of the x and y axes
32+
"""
33+
#set parameters
34+
self.display=display
35+
self.ul_x=ul_x
36+
self.ul_y=ul_y
37+
self.br_x=br_x
38+
self.br_y=br_y
39+
self.ax_color=ax_color
40+
self.min_x=min_x
41+
self.max_x=max_x
42+
self.min_y=min_y
43+
self.max_y=max_y
44+
self.x_ticks_num=x_ticks_num
45+
self.y_ticks_num=y_ticks_num
46+
# Load a small font
47+
self.x_font_size=8
48+
self.y_font_size=10
49+
self.display.font=Font('fonts/Small_Fonts8x10.c', self.x_font_size, self.y_font_size,char_spacing=0, line_spacing=1)
50+
# Define and draw plotting area (taking out space for the ticks and labels)
51+
self.tick_size=3
52+
self.top_margin=int(self.y_font_size/2)+1
53+
self.bottom_margin=12
54+
self.left_margin=20
55+
self.x_origin=self.ul_x+self.left_margin
56+
self.x_range=self.br_x-self.x_origin
57+
self.y_origin=self.br_y-self.bottom_margin
58+
self.y_range=self.y_origin-self.top_margin-self.ul_y
59+
self.display.draw_rect(self.ul_x+self.left_margin, self.ul_y+self.top_margin, self.br_x, self.br_y-self.bottom_margin,self.ax_color)
60+
self.display.settextcolor(self.ax_color)
61+
# prepare for legend
62+
self.line_labels=[]
63+
self.line_colors=[]
64+
#draw axes
65+
self.draw_axes_x()
66+
self.draw_axes_y()
67+
68+
def draw_axes_x(self):
69+
# draw ticks
70+
for i in range(self.x_ticks_num+1):
71+
x_tick=self.ul_x+self.left_margin+int(i*self.x_range/self.x_ticks_num)
72+
self.display.draw_fastVline(x_tick,self.br_y-self.bottom_margin-self.tick_size,self.br_y-self.bottom_margin,self.ax_color)
73+
x_tick_val=str(round(self.min_x+(i*(self.max_x-self.min_x)/self.x_ticks_num),2))
74+
self.display.settextcursor(x_tick-int(self.display.strlen(x_tick_val)/2), self.br_y-self.bottom_margin+1)
75+
self.display.printh(x_tick_val)
76+
77+
def draw_axes_y(self):
78+
# draw ticks
79+
for i in range(self.y_ticks_num+1):
80+
y_tick=self.br_y-self.bottom_margin-int(i*self.y_range/self.y_ticks_num)
81+
self.display.draw_fastHline(self.ul_x+self.left_margin,self.ul_x+self.left_margin+self.tick_size,y_tick,self.ax_color)
82+
self.display.settextcursor(self.ul_x, y_tick-int(self.y_font_size/2))
83+
y_tick_val=round(self.min_y+(i*(self.max_y-self.min_y)/self.y_ticks_num),2)
84+
self.display.printh(str(y_tick_val))
85+
86+
def draw_labels(self):
87+
x1_line=self.x_origin+10
88+
for i in range(len(self.line_labels)):
89+
y1_line=self.top_margin+self.ul_y+int(self.y_font_size/2)+i*self.y_font_size+1
90+
self.display.draw_fastHline(x1_line,x1_line+10,y1_line,self.line_colors[i])
91+
self.display.settextcursor(x1_line+10+2, y1_line-int(self.y_font_size/2))
92+
self.display.settextcolor(self.line_colors[i])
93+
self.display.printh(self.line_labels[i])
94+
95+
96+
class Line:
97+
"""An x.y graph object (line) for the VGA 800x600 display.
98+
99+
Note: All coordinates are zero based.
100+
"""
101+
102+
def __init__(self, plot, x_data, y_data, line_color=GREEN,label="unknown"):
103+
"""Initialize line.
104+
105+
Args:
106+
plot : the VGA 800x600 plot object
107+
x_data : list of x values
108+
y_data : list of y value
109+
plot_color : color of the line
110+
"""
111+
#set parameters
112+
self.plot=plot
113+
self.x_data=x_data
114+
self.y_data=y_data
115+
self.x_pixdata=[]
116+
self.y_pixdata=[]
117+
self.color=line_color
118+
self.plot.line_labels.append(label)
119+
self.plot.line_colors.append(self.color)
120+
self.plot.draw_labels()
121+
self.is_first_point=True
122+
#draw line
123+
if len(self.x_data):
124+
self.draw()
125+
126+
def draw(self):
127+
for i in range(len(self.x_data)):
128+
plotx=self.plot.x_origin+int((self.x_data[i]*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
129+
ploty=self.plot.y_origin-int((self.y_data[i]*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
130+
if i>0:
131+
self.plot.display.draw_line(self.x_pixdata[-1],self.y_pixdata[-1],plotx,ploty,self.color)
132+
else :
133+
self.plot.display.draw_pix(plotx,ploty,self.color)
134+
self.x_pixdata.append(plotx)
135+
self.y_pixdata.append(ploty)
136+
137+
def add_data(self,x,y):
138+
if not len(self.x_data):
139+
plotx=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
140+
ploty=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
141+
self.plot.display.draw_pix(plotx,ploty,self.color)
142+
self.x_data.append(x)
143+
self.y_data.append(y)
144+
self.x_pixdata.append(plotx)
145+
self.y_pixdata.append(ploty)
146+
else:
147+
plotx=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
148+
ploty=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
149+
self.plot.display.draw_line(self.x_pixdata[-1],self.y_pixdata[-1],plotx,ploty,self.color)
150+
self.x_pixdata.append(plotx)
151+
self.y_pixdata.append(ploty)
152+
self.x_data.append(x)
153+
self.y_data.append(y)
154+
155+
def add_data_ns(self,x,y,draw_line=True):
156+
# add_dat without storage (saves memory)
157+
if self.is_first_point:
158+
self.plotx0=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
159+
self.ploty0=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
160+
self.plot.display.draw_pix(self.plotx0,self.ploty0,self.color)
161+
self.is_first_point=False
162+
else:
163+
plotx=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
164+
ploty=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
165+
if draw_line:
166+
self.plot.display.draw_line(self.plotx0,self.ploty0,plotx,ploty,self.color)
167+
self.plotx0=plotx
168+
self.ploty0=ploty
169+
else :
170+
self.plot.display.draw_pix(plotx,ploty,self.color)
171+
172+
def add_data_moy(self,x,y,num_samples=5):
173+
# add_dat with mean calc over the last num_samples values
174+
# we only store the last num_samples value
175+
if not len(self.y_data):
176+
plotx=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
177+
ploty=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
178+
self.plot.display.draw_pix(plotx,ploty,self.color)
179+
for i in range(num_samples):
180+
self.y_data.append(y)
181+
self.x_pixdata.append(plotx)
182+
self.y_pixdata.append(ploty)
183+
else:
184+
y_last_sum=0
185+
for val in self.y_data:
186+
y_last_sum+=val
187+
y_mean=(y+y_last_sum)/(num_samples+1)
188+
y=y_mean
189+
plotx=self.plot.x_origin+int((x*self.plot.x_range/(self.plot.max_x-self.plot.min_x)))
190+
ploty=self.plot.y_origin-int((y*self.plot.y_range/(self.plot.max_y-self.plot.min_y)))
191+
self.plot.display.draw_line(self.x_pixdata[-1],self.y_pixdata[-1],plotx,ploty,self.color)
192+
self.x_pixdata.pop(0)
193+
self.x_pixdata.append(plotx)
194+
self.y_pixdata.pop(0)
195+
self.y_pixdata.append(ploty)
196+
self.y_data.pop(0)
197+
self.y_data.append(y)
198+

VGA_test.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Hugmaingauche 2025
2+
# test file for use with the micropython VGA library
3+
# https://github.com/HughMaingauche/PICO2-VGA-Micropython
4+
5+
from VGA.VGA_fonts import Font
6+
from VGA.VGA_800x600 import screen_800x600
7+
8+
display = screen_800x600()
9+
display.VGA_init()
10+
11+
# 3 bit color names
12+
RED = 0b001
13+
GREEN = 0b010
14+
BLUE = 0b100
15+
YELLOW = 0b011
16+
BLACK = 0
17+
WHITE = 0b111
18+
CYAN = 0b110
19+
MAGENTA = 0b101
20+
21+
text1="L\'est s\'empourpra d\'une teinte de vieux sang et bientot \
22+
le soleil apparut, tremblant comme un vieillard frileux. Le sol etait voile de brume ; Cugel pouvait a peine se rendre compte \
23+
qu\'ils passaient au-dessus d\'une contree de noires montagnes et de gouffres tenebreux.\n"
24+
25+
display.draw_rect(1,1,display.H_res,display.V_res,GREEN)
26+
27+
print('Loading fonts...')
28+
29+
print('Loading Arial')
30+
display.font=Font('fonts/Arial13x13.c', 13, 13)
31+
display.settextcolor(CYAN)
32+
display.printh("Arial13x13: ")
33+
display.settextcolor(WHITE)
34+
display.printh(text1+"\n")
35+
36+
37+
print('Loading Calibri')
38+
display.font=Font('fonts/Calibri12x11.c', 12, 11)
39+
display.settextcolor(MAGENTA)
40+
display.printh("\nCalibri12x11: ")
41+
display.settextcolor(WHITE)
42+
display.printh(text1+"\n")
43+
44+
#
45+
print('Loading Cascadia')
46+
display.font=Font('fonts/Cascadia_Code7x14.c', 7, 14)
47+
display.settextcolor(BLUE)
48+
display.printh("\nCascadia_Code7x14: ")
49+
display.settextcolor(WHITE)
50+
display.printh(text1+"\n")
51+
#
52+
print('Loading robotronsmall')
53+
display.font=Font('fonts/Robotron7x11.c', 7, 11, start_letter=32, letter_count=96)
54+
display.settextcolor(GREEN)
55+
display.printh("ROBOTRON7X11: ")
56+
display.settextcolor(WHITE)
57+
display.printh(text1+"\n")
58+
#
59+
print('Loading Small_Fonts7x8.c')
60+
display.font=Font('fonts/Small_Fonts7x8.c', 7, 8, start_letter=32, letter_count=96,char_spacing=1, line_spacing=2)
61+
display.settextcolor(RED)
62+
display.printh("Small_Fonts7x8: ")
63+
display.settextcolor(WHITE)
64+
display.printh(text1+"\n")
65+
#
66+
print('Loading Small_Fonts9x11.c')
67+
display.font=Font('fonts/Small_Fonts9x11.c', 9, 11, start_letter=32, letter_count=96,char_spacing=1, line_spacing=2)
68+
display.settextcolor(YELLOW)
69+
display.printh("Small_Fonts9x11: ")
70+
display.settextcolor(WHITE)
71+
display.printh(text1+"\n")
72+
73+
74+
75+
print('Fonts loaded.')
76+
#
77+
# Drawing a simple 8 color checker
78+
for h in range(6,10):
79+
for i in range(0,60):
80+
for k in range(10):
81+
col=(h+k)%8
82+
display.draw_fastHline(k*80,k*80+80,h*60+i,col)
83+
#

0 commit comments

Comments
 (0)