"""Module 5 — Bus I2C et SPI.""" import matplotlib.pyplot as plt from outils import boite, toile from style import BLEU, CM, ENCRE, GRIS, ORANGE, VERT, Figure def bus_i2c(): fig, ax = toile(16, 6.4) maitre = boite(ax, 1.9, 3.2, 3.0, 2.6, couleur=BLEU) ax.text(1.9, 3.75, "ESP32-S3", ha="center", fontsize=10, color=BLEU, fontweight="bold") ax.text(1.9, 2.95, "maître\n(génère SCL)", ha="center", va="center", fontsize=8, color=ENCRE) y_sda, y_scl = 4.0, 2.4 ax.plot([3.4, 15.6], [y_sda, y_sda], color=BLEU, lw=2) ax.plot([3.4, 15.6], [y_scl, y_scl], color=ORANGE, lw=2) ax.text(3.5, y_sda + 0.15, "SDA (GPIO8) — données", fontsize=8.5, color=BLEU, va="bottom") ax.text(3.5, y_scl + 0.15, "SCL (GPIO9) — horloge", fontsize=8.5, color=ORANGE, va="bottom") # Résistances de tirage ax.plot([7.5, 9.5], [5.9, 5.9], color=ENCRE, lw=1.3) ax.text(8.5, 6.05, "3V3", ha="center", fontsize=8, color=ENCRE) for x, yb in ((7.8, y_sda), (9.2, y_scl)): ax.plot([x, x], [5.9, 5.6], color=ENCRE, lw=1.3) ax.add_patch(plt.Rectangle((x - 0.15, 4.7 if yb == y_sda else 4.2), 0.3, 0.9 if yb == y_sda else 1.4, fill=False, ec=ENCRE, lw=1.3)) ax.plot([x, x], [4.7 if yb == y_sda else 4.2, yb], color=ENCRE, lw=1.3) ax.plot(x, yb, "o", color=ENCRE, ms=4) ax.text(9.5, 5.2, "résistances de tirage\n(souvent déjà sur les modules)", fontsize=7.5, color=GRIS, va="center") # Esclaves for x, nom, adr in ((6.0, "Écran OLED\nSSD1306", "0x3C"), (11.5, "Capteur\nBME280", "0x76"), (14.6, "autre\nmodule", "0x??")): boite(ax, x, 0.85, 2.7, 1.45, f"{nom}\nadresse {adr}", couleur=VERT, taille=7.2) for dx, yb, c in ((-0.5, y_sda, BLEU), (0.5, y_scl, ORANGE)): ax.plot([x + dx, x + dx], [1.5, yb], color=c, lw=1.5) ax.plot(x + dx, yb, "o", color=c, ms=4) ax.text(1.9, 1.05, "tous sur les 2 mêmes fils :\nchacun répond\nà son adresse", ha="center", va="center", fontsize=7.2, color=GRIS, style="italic") return fig def trame_i2c(): # Écriture vers l'adresse 0x3C (0111100), R/W = 0, ACK, octet 0xAF, ACK adresse = [0, 1, 1, 1, 1, 0, 0] donnee = [1, 0, 1, 0, 1, 1, 1, 1] bits = adresse + [0] + [0] + donnee + [0] roles = ["adr"] * 7 + ["rw"] + ["ack"] + ["data"] * 8 + ["ack"] fig, ax = plt.subplots(figsize=(16 * CM, 5.6 * CM)) t0 = 1.0 scl_x, scl_y, sda_x, sda_y = [0, t0], [1, 1], [0, 0.5], [1, 1] sda_x += [0.5] sda_y += [0] # START : SDA descend pendant que SCL est haut scl_x += [t0] scl_y += [0] for k, b in enumerate(bits): x = t0 + k scl_x += [x + 0.5, x + 0.5, x + 1, x + 1] scl_y += [0, 1, 1, 0] sda_x += [x + 0.15, x + 0.15] sda_y += [sda_y[-1], b] fin = t0 + len(bits) scl_x += [fin + 0.4, fin + 0.4, fin + 1.4] scl_y += [0, 1, 1] sda_x += [fin + 0.15, fin + 0.15, fin + 0.8, fin + 0.8, fin + 1.4] sda_y += [sda_y[-1], 0, 0, 1, 1] # STOP : SDA monte pendant que SCL est haut ax.plot(scl_x, [v + 2 for v in scl_y], color=ORANGE, lw=1.6) ax.plot(sda_x, sda_y, color=BLEU, lw=1.6) couleurs = {"adr": BLEU, "rw": BLEU, "ack": VERT, "data": BLEU} for k, (b, r) in enumerate(zip(bits, roles)): x = t0 + k ax.axvspan(x, x + 1, ymin=0.08, ymax=0.42, color=couleurs[r], alpha=0.07 if r != "ack" else 0.2, lw=0) ax.text(x + 0.5, -0.35, str(b), ha="center", fontsize=7.5, color=ENCRE) groupes = [(0, 1, "START", ORANGE), (t0, t0 + 7, "adresse 0x3C (7 bits)", BLEU), (t0 + 7, t0 + 8, "R/W", BLEU), (t0 + 8, t0 + 9, "ACK", VERT), (t0 + 9, t0 + 17, "donnée (8 bits)", BLEU), (t0 + 17, t0 + 18, "ACK", VERT), (fin, fin + 1.4, "STOP", ORANGE)] for a, b, txt, c in groupes: ax.annotate("", xy=(a + 0.05, 3.45), xytext=(b - 0.05, 3.45), arrowprops=dict(arrowstyle="|-|", color=c, lw=0.9, mutation_scale=3)) ax.text((a + b) / 2, 3.6, txt, ha="center", va="bottom", fontsize=7.3, color=c, fontweight="bold") ax.text(-0.3, 2.5, "SCL", ha="right", va="center", fontsize=9, fontweight="bold", color=ORANGE) ax.text(-0.3, 0.5, "SDA", ha="right", va="center", fontsize=9, fontweight="bold", color=BLEU) ax.text(fin + 1.4, -0.75, "ACK (en vert) : c'est l'esclave qui tire SDA à 0 pour accuser réception", ha="right", fontsize=7.5, color=VERT) ax.set_xlim(-0.4, fin + 1.6) ax.set_ylim(-0.95, 4.2) ax.axis("off") fig.tight_layout() return fig def bus_spi(): fig, ax = toile(16, 6.4) boite(ax, 2.0, 3.2, 3.2, 4.4, couleur=BLEU) ax.text(2.0, 4.55, "ESP32-S3\nmaître", ha="center", va="center", fontsize=9.5, color=BLEU, fontweight="bold") lignes = [("SCK", 4.2, ORANGE, "horloge"), ("MOSI", 3.5, BLEU, "maître → esclave"), ("MISO", 2.8, VERT, "esclave → maître")] for nom, yy, c, role in lignes: ax.plot([3.6, 15.4], [yy, yy], color=c, lw=2) ax.text(3.75, yy + 0.08, f"{nom} — {role}", fontsize=8, color=c, va="bottom") esclaves = [(9.0, "Écran TFT", "CS1"), (13.5, "Carte SD", "CS2")] for i, (x, nom, cs) in enumerate(esclaves): boite(ax, x, 0.8, 2.8, 1.1, nom, couleur=GRIS, taille=8.5) for dx, (_, yy, c, _r) in zip((-0.9, -0.3, 0.3), lignes): ax.plot([x + dx, x + dx], [1.35, yy], color=c, lw=1.4) ax.plot(x + dx, yy, "o", color=c, ms=3.5) ycs = 1.9 - i * 0.45 ax.plot([3.6, x + 0.9, x + 0.9], [ycs, ycs, 1.35], color=ENCRE, lw=1.4, ls="--" if i else "-") ax.text(3.75, ycs + 0.06, cs, fontsize=7.8, color=ENCRE, va="bottom") ax.text(15.4, 5.6, "SCK, MOSI, MISO : partagés\nCS (Chip Select) : une ligne par périphérique,\nle maître met à 0 celle de son interlocuteur", ha="right", va="center", fontsize=7.8, color=GRIS, style="italic") return fig FIGURES = [ Figure("m05-bus-i2c", bus_i2c), Figure("m05-trame-i2c", trame_i2c), Figure("m05-bus-spi", bus_spi), ]