-
Notifications
You must be signed in to change notification settings - Fork 71
Open
Description
Hello
Two months ago, it works. i build with latest source and now it doesm't. I am driving ST7735 and AD9833 in the same SPI bus, so MOSI and CLK pins are connected to same pins on Waveshare Zero C6 board. Now, AD9833 is still working but the LCD only see random dots.
import lcd_bus
from micropython import const
import machine
from time import sleep
import st7735
import lvgl as lv
import utime as time
from fs_driver import fs_register
from machine import Pin
import AD9833
# AD9833 c6 zero
# AD9833_SDO = 1
# AD9833_CLK = 2
# AD9833_CS = 22
# AD9833 c6 zero
AD9833_SDO = 15
AD9833_CLK = 14
AD9833_CS = 22
# display settings
_WIDTH = 128
_HEIGHT = 128
_BL = 21
_RST = 18
_DC = 19
_MOSI = 15 # SDA
# _MISO = 20
_SCK = 14 # SCL
_HOST = 1 # SPI2
_LCD_CS = 20
_LCD_FREQ = 4000000
_OFFSET_X = 2
_OFFSET_Y = 3
# Buttons
BUTTON0 = 4
ROTATE_BUTTON_S1 = 5
ROTATE_BUTTON_S2 = 3
selected = 0
selectedFreqBtn = 0
currentFreq = 4000
currentPhase = 0 # Current phase in degrees
def format_frequency(freq):
"""Format frequency display with appropriate units"""
if freq < 1000:
return f"{freq} Hz"
elif freq < 1000000:
khz = freq / 1000.0
if freq % 1000 == 0:
return f"{khz} kHz"
else:
return f"{khz:.3f} kHz"
else:
mhz = freq / 1000000.0
if freq % 1000000 == 0:
return f"{mhz} MHz"
else:
return f"{mhz:.6f} MHz"
def drawMenu():
# Only update button backgrounds and frequency label
global menu_buttons, selected
for i, btn in enumerate(menu_buttons):
if i == selected:
btn.set_style_bg_color(lv.color_hex(0xffffff), 0)
else:
btn.set_style_bg_color(lv.color_hex(0x8888dd), 0)
spi_bus = machine.SPI.Bus(
host=_HOST,
mosi=_MOSI,
# miso=_MISO,
sck=_SCK
)
display_bus = lcd_bus.SPIBus(
spi_bus=spi_bus,
freq=_LCD_FREQ,
dc=_DC,
cs=_LCD_CS,
)
display = st7735.ST7735(
data_bus=display_bus,
display_width=_WIDTH,
display_height=_HEIGHT,
backlight_pin=_BL,
reset_pin=_RST,
reset_state=st7735.STATE_LOW,
backlight_on_state=st7735.STATE_HIGH,
color_space=lv.COLOR_FORMAT.RGB565,
color_byte_order=st7735.BYTE_ORDER_BGR,
rgb565_byte_swap=True,
offset_x=_OFFSET_X,
offset_y=_OFFSET_Y
)
# Initialize display
display.init(st7735.TYPE_R_RED)
display.set_rotation(lv.DISPLAY_ROTATION._180)
display.set_backlight(100)
# Create screen
scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)
scrn.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
fs_drv = lv.fs_drv_t()
fs_register(fs_drv, "S")
img = lv.image(scrn)
img.set_src("S:blue.png")
img.set_size(20, 20)
img.set_pos(0, 5)
label = lv.label(scrn)
label.set_text("Func Generator")
label.set_pos(24, 8)
label.set_style_text_color(lv.color_hex(0xffffff), 0)
label.set_style_text_font(lv.font_montserrat_12, 0)
button0 = Pin(BUTTON0, Pin.IN, Pin.PULL_UP) # Button pin
# Rotary encoder pins
rotary_s1 = Pin(ROTATE_BUTTON_S1, Pin.IN, Pin.PULL_UP)
rotary_s2 = Pin(ROTATE_BUTTON_S2, Pin.IN, Pin.PULL_UP)
# Initialize rotary encoder state
rotary_s1_prev = rotary_s1.value()
rotary_s2_prev = rotary_s2.value()
# --- Create menu buttons and labels once ---
freq = ["SQU", "SIN", "TRI"]
currentFreqLabelIndex = 0
menu_buttons = []
btn = lv.button(scrn)
btn.set_pos(0, 30)
btn.set_size(75, 20) # Reduced width for waveform button
freqLbl = lv.label(btn)
freqLbl.set_text(freq[0])
freqLbl.set_style_text_color(lv.color_hex(0x000000), 0)
freqLbl.set_style_text_font(lv.font_montserrat_12, 0)
freqLbl.center()
menu_buttons.append(btn)
# PHASE button next to waveform button
phase_btn = lv.button(scrn)
phase_btn.set_pos(80, 30) # Position next to waveform button
phase_btn.set_size(45, 20)
phase_btn_lbl = lv.label(phase_btn)
phase_btn_lbl.set_text("PHASE")
phase_btn_lbl.set_style_text_color(lv.color_hex(0x000000), 0)
phase_btn_lbl.set_style_text_font(lv.font_montserrat_12, 0)
phase_btn_lbl.center()
menu_buttons.append(phase_btn) # Insert PHASE button as second button
for i, label in enumerate(["1Hz", "10Hz", "100Hz", "1kHz", "10kHz", "1MHz"]):
btn = lv.button(scrn)
if i < 3:
btn.set_pos(i*40+i*3, 55)
else:
btn.set_pos((i-3)*40+(i-3)*3, 80)
btn.set_size(40, 20)
lbl = lv.label(btn)
lbl.set_text(label)
lbl.set_style_text_color(lv.color_hex(0x000000), 0)
lbl.set_style_text_font(lv.font_montserrat_12, 0)
lbl.center()
menu_buttons.append(btn)
# --- Create frequency label once ---
freq_label = lv.label(scrn)
freq_label.set_pos(5, 100)
freq_label.set_style_text_color(lv.color_hex(0xffffff), 0)
freq_label.set_style_text_font(lv.font_montserrat_16, 0)
freq_label.set_text(format_frequency(currentFreq))
# --- Create phase label ---
phase_label = lv.label(scrn)
phase_label.set_pos(5, 115)
phase_label.set_style_text_color(lv.color_hex(0xffffff), 0)
phase_label.set_style_text_font(lv.font_montserrat_12, 0)
phase_label.set_text(f"Phase: {currentPhase}°")
drawMenu()
# temp.value(1)
# display_bus.deinit()
ad9833 = AD9833.AD9833(sdo=AD9833_SDO, clk=AD9833_CLK, cs=AD9833_CS, fmclk=25)
ad9833.set_frequency(currentFreq, 0)
ad9833.set_phase(currentPhase, 0, rads=False)
ad9833.set_phase((currentPhase + 180) % 360, 1, rads=False)
ad9833.select_freq_phase(0, 0)
ad9833.set_mode('SQUARE')
time.sleep(2)
drawMenu()
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
while True:
# time.sleep_ms(20)
# sleep(0.2)
b = False
# Button handling
if not button0.value(): # Button pressed
selected = (selected + 1) % len(menu_buttons)
print(selected)
drawMenu()
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
while not button0.value():
pass # Wait for release (debounce)
# Rotary encoder handling
s1 = rotary_s1.value()
s2 = rotary_s2.value()
if s1 != rotary_s1_prev or s2 != rotary_s2_prev:
# Detect rotation direction
if selected == 0 and rotary_s1_prev == 1 and s1 == 0: # S1 falling edge
if s2 == 0: # Clockwise
currentFreqLabelIndex = (currentFreqLabelIndex + 1) % len(freq)
print(f"Rotary CW: selected {selected}")
freqLbl.set_text(freq[currentFreqLabelIndex])
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
elif selected == 0 and rotary_s2_prev == 1 and s2 == 0: # S2 falling edge
if s1 == 0: # Counter-clockwise
currentFreqLabelIndex = (currentFreqLabelIndex - 1) % len(freq)
print(f"Rotary CCW: selected {selected}")
freqLbl.set_text(freq[currentFreqLabelIndex])
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
elif selected > 1 and selected < 8 and rotary_s1_prev == 1 and s1 == 0: # S1 falling edge
if s2 == 0: # Clockwise
print(f"Rotary CW: selected {selected}")
if selected == 2:
currentFreq += 1
elif selected == 3:
currentFreq += 10
elif selected == 4:
currentFreq += 100
elif selected == 5:
currentFreq += 1000
elif selected == 6:
currentFreq += 10000
elif selected == 7:
currentFreq += 1000000
if currentFreq > 12600000:
currentFreq = 12600000
freq_label.set_text(format_frequency(currentFreq))
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
elif selected > 1 and selected < 8 and rotary_s2_prev == 1 and s2 == 0: # S2 falling edge
if s1 == 0: # Counter-clockwise
if selected == 2:
currentFreq -= 1
elif selected == 3:
currentFreq -= 10
elif selected == 4:
currentFreq -= 100
elif selected == 5:
currentFreq -= 1000
elif selected == 6:
currentFreq -= 10000
elif selected == 7:
currentFreq -= 1000000
if currentFreq < 0:
currentFreq = 0
freq_label.set_text(format_frequency(currentFreq))
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
elif selected == 1 and rotary_s1_prev == 1 and s1 == 0: # Phase adjustment - S1 falling edge
if s2 == 0: # Clockwise - increase phase
currentPhase = (currentPhase + 10) % 360
phase_label.set_text(f"Phase: {currentPhase}°")
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
elif selected == 1 and rotary_s2_prev == 1 and s2 == 0: # Phase adjustment - S2 falling edge
if s1 == 0: # Counter-clockwise - decrease phase
currentPhase = (currentPhase - 10) % 360
phase_label.set_text(f"Phase: {currentPhase}°")
lv.refr_now(lv.screen_active().get_display())
lv.task_handler()
b = True
rotary_s1_prev = s1
rotary_s2_prev = s2
time.sleep_ms(10) # Debounce delay
if b:
print(currentFreqLabelIndex, currentFreq, currentPhase)
if currentFreqLabelIndex == 0:
ad9833.set_frequency(currentFreq, 0)
# ad9833.select_freq_phase(0, 0)
ad9833.set_mode('SQUARE')
elif currentFreqLabelIndex == 1:
ad9833.set_frequency(currentFreq, 0)
ad9833.set_phase((currentPhase + 180) % 360, 0, rads=False)
# ad9833.set_phase((currentPhase + 180) % 360, 1, rads=False)
ad9833.select_freq_phase(0, 0)
ad9833.set_mode('SIN')
elif currentFreqLabelIndex == 2:
ad9833.select_freq_phase(0, 0)
ad9833.set_frequency(currentFreq, 0)
ad9833.set_mode('TRIANGLE')
"""AD9833, micropython module to use the AD983X
programable waveform generators
created June 2, 2023
modified June 2, 2023
"""
"""
Copyright 2023 Owain Martin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from math import pi, radians
import machine
import utime as time
class AD9833:
def __init__(self, sdo, clk, cs, fmclk=25):
"""__init__, set up AD9833 object"""
self.fmclk = fmclk*10**6
# set up SPI connection details
# had to use phase = 1 even though the datasheet
# specifies phase = 0, on Pi SBC used phase = 0.
self.sdo = machine.Pin(sdo)
self.clk = machine.Pin(clk)
self.cs = machine.Pin(cs, machine.Pin.OUT)
self.cs.value(1)
# Use software SPI to avoid conflicts with LCD hardware SPI
# self.spi = machine.SoftSPI(
# baudrate=1000000, # Lower speed for reliability
# polarity=1,
# phase=1,
# sck=machine.Pin(clk),
# mosi=machine.Pin(sdo),
# miso=machine.Pin(0) # AD9833 doesn't need MISO
# )
_HOST=1 # Use separate SPI host to avoid conflicts with LCD
self.spi = machine.SPI.Bus(
host=_HOST,
sck=machine.Pin(clk),
mosi=machine.Pin(sdo),
# miso=machine.Pin(0) # AD9833 doesn't need MISO
)
# self.spi = machine.SPI(_HOST, baudrate = 4000000, polarity = 1, phase = 1, sck= self.clk, mosi = self.sdo)
self.set_control_reg(B28=1, RESET=1)
self.mode = "RESET"
self.writeMode = "BOTH"
self.freq0 = 0
self.freq1 = 0
self.phase0 = 0
self.phase1 = 0
return
def write_data(self, data):
"""write_data, function to write data to
the AD983x chip"""
# print(data)
data = bytearray(data) # creates buffer object
self.cs.value(0)
self.spi.write(data)
self.cs.value(1)
return
def set_control_reg(self, B28=1, HLB=0, FS=0, PS=0, RESET=0, SLP1=0, SLP12=0, OP=0, DIV2=0, MODE=0):
"""set_control_reg, function to set any/all of the bits
of the AD9833 control register"""
self.B28 = B28
self.HLB = HLB
self.FS = FS
self.PS = PS
self.RESET = RESET
self.SLP1 = SLP1
self.SLP12 = SLP12
self.OP = OP
self.DIV2 = DIV2
self.MODE = MODE
controlReg = (B28 << 13) + (HLB << 12) + (FS << 11) + (PS << 10) + (RESET <<
8) + (SLP1 << 7) + (SLP12 << 6) + (OP << 5) + (DIV2 << 3) + (MODE << 1)
# print(hex(controlReg))
controlRegList = [(controlReg & 0xFF00) >> 8, controlReg & 0x00FF]
self.write_data(controlRegList)
return
def set_frequency(self, fout, freqSelect):
"""set_frequency, function to set the frequency registers"""
# calculate frequncy register value from fout
freqR = int((fout*pow(2, 28))/self.fmclk)
# split frequency register value into 2
# 14 bit segments
fMSB = (freqR & 0xFFFC000) >> 14
fLSB = freqR & 0x3FFF
# add register address to each 14 bit segment
if freqSelect == 0:
addr = 0b01
self.freq0 = fout
else:
addr = 0b10
self.freq1 = fout
fMSB = fMSB + (addr << 14)
fLSB = fLSB + (addr << 14)
# print(hex(fLSB), hex(fMSB))
# split fMSB & fLSB into 8 bits segements
# for writing to AD9833 freq registers
fLSBList = [(fLSB & 0xFF00) >> 8, fLSB & 0x00FF]
fMSBList = [(fMSB & 0xFF00) >> 8, fMSB & 0x00FF]
fBoth = fLSBList + fMSBList
if self.writeMode == 'MSB':
self.write_data(fMSBList)
elif self.writeMode == 'LSB':
self.write_data(fLSBList)
else:
self.write_data(fBoth)
return
def set_phase(self, pout, phaseSelect, rads=True):
"""set_phase, function to set the phase registers"""
# calculate the phase register value
if rads == False:
# convert degrees to radians
pout = radians(pout)
phaseR = int(pout*4096/(2*pi))
# add phase address
# 12 bit regValue
# 1 bit - don't care
# 3 bit address
phaseR = phaseR + (0b11 << 14) + (phaseSelect << 13)
# split phaseR into 8 bits segements
# for writing to AD9833 phase registers
phaseRList = [(phaseR & 0xFF00) >> 8, phaseR & 0x00FF]
self.write_data(phaseRList)
return
def set_mode(self, mode='SIN'):
"""set_mode, function to set the mode/output type of the
AD9833 as well as the active frequency and phase registers.
Valid modes include: 'RESET', 'OFF', 'SIN','TRIANGLE',
'SQUARE', 'SQUARE/2'"""
print(mode)
self.mode = mode
if mode == 'SIN':
self.set_control_reg(B28=self.B28, HLB=self.HLB,
FS=self.FS, PS=self.PS, RESET=0, MODE=0)
elif mode == 'TRIANGLE':
self.set_control_reg(B28=self.B28, HLB=self.HLB,
FS=self.FS, PS=self.PS, RESET=0, MODE=1)
elif mode == 'SQUARE':
self.set_control_reg(B28=self.B28, HLB=self.HLB, FS=self.FS, PS=self.PS, RESET=0, SLP12=1,
OP=1, DIV2=1, MODE=0)
elif mode == 'SQUARE/2':
self.set_control_reg(B28=self.B28, HLB=self.HLB, FS=self.FS, PS=self.PS, RESET=0, SLP12=1,
OP=1, DIV2=0, MODE=0)
elif mode == 'RESET':
self.set_control_reg(B28=self.B28, HLB=self.HLB,
FS=self.FS, PS=self.PS, RESET=1)
elif mode == 'OFF':
self.set_control_reg(B28=self.B28, HLB=self.HLB,
FS=self.FS, PS=self.PS, RESET=1, SLP1=1, SLP12=1)
return
def set_write_mode(self, writeMode='BOTH'):
"""set_write_mode, function to set the B28 and HLB bits in the
control register which control how data is written to the
frequency registers. Valid value for writeMode are 'BOTH',
'MSB' and 'LSB'"""
B28 = 1
HLB = 0
self.writeMode = 'BOTH'
if writeMode == 'MSB':
B28 = 0
HLB = 1
self.writeMode = 'MSB'
elif writeMode == 'LSB':
B28 = 0
HLB = 0
self.writeMode = 'LSB'
self.set_control_reg(B28=B28, HLB=HLB, FS=self.FS, PS=self.PS, RESET=self.RESET, SLP1=self.SLP1,
SLP12=self.SLP12, OP=self.OP, DIV2=self.DIV2, MODE=self.MODE)
return
def select_freq_phase(self, FS, PS):
"""select_freq_phase, function to select which frequency and phase register
the AD9833 uses and changes to them"""
self.set_control_reg(B28=self.B28, HLB=self.HLB, FS=FS, PS=PS, RESET=self.RESET, SLP1=self.SLP1,
SLP12=self.SLP12, OP=self.OP, DIV2=self.DIV2, MODE=self.MODE)
return
if __name__ == "__main__":
# ad9833 = AD9833(sdo = 19, clk = 18, cs = 17, fmclk = 25)
# ad9833 = AD9833(sdo=3, clk=2, cs=1, fmclk=25)
ad9833 = AD9833(sdo=8, clk=7, cs=3, fmclk=25)
delay = 10
ad9833.set_frequency(1100, 0)
ad9833.set_frequency(2200, 1)
ad9833.set_phase(0, 0, rads=False)
ad9833.set_phase(180, 1, rads=False)
ad9833.select_freq_phase(0, 0)
ad9833.set_mode('SIN')
print('Sin')
time.sleep(delay)
ad9833.set_write_mode('LSB')
ad9833.set_frequency(1200, 0)
print('LSB')
time.sleep(delay)
ad9833.select_freq_phase(1, 0)
time.sleep(delay)
ad9833.set_mode('TRIANGLE')
print('TRIANGLE')
time.sleep(delay)
# freq 0 Triangle wave output
ad9833.select_freq_phase(0, 0)
ad9833.set_mode('TRIANGLE')
print('TRIANGLE')
time.sleep(delay)
# freq 0 Square wave output
ad9833.set_mode('SQUARE')
print('SQUARE')
time.sleep(delay)
# freq 0 divide by 2 Square wave output
ad9833.set_mode('SQUARE/2')
print('SQUARE/2')
time.sleep(delay)
# change freq 0 to 1700 Hz, Sin wave output
ad9833.set_write_mode('BOTH')
ad9833.set_frequency(1700, 0)
ad9833.set_mode('SIN')
print('BOTH')
time.sleep(delay)
ad9833.set_mode('OFF')
thanks
Metadata
Metadata
Assignees
Labels
No labels