├── .gitignore ├── ConcurrentBlink └── concurrentblink.go ├── README.md ├── blink ├── blink.go └── go.mod ├── channels └── channels.go ├── go.mod ├── gpio-interrupts ├── go.mod └── main.go ├── images ├── pragmatik-logo-1852x484.png └── pragmatik-logo-200x53.png ├── more-interrupts └── main.go ├── pwm-blink └── pwm-blink.go ├── slides ├── pragmatik.css ├── pragmatik.css.map └── pragmatik.scss └── spi_74hc595 └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .DS_Store 3 | .idea -------------------------------------------------------------------------------- /ConcurrentBlink/concurrentblink.go: -------------------------------------------------------------------------------- 1 | // ConcurrentBlink.go 2 | 3 | package main 4 | 5 | import ( 6 | "machine" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | led := machine.LED 12 | led.Configure(machine.PinConfig{ 13 | Mode: machine.PinOutput, 14 | }) 15 | 16 | go printHello() 17 | 18 | for { 19 | led.High() 20 | time.Sleep(500 * time.Millisecond) 21 | led.Low() 22 | time.Sleep(500 * time.Millisecond) 23 | } 24 | } 25 | 26 | func printHello() { 27 | for { 28 | println("hello concurrently") 29 | time.Sleep(time.Second) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyGo and Raspberry Pi Pico Tutorials 2 | 3 | This repository contains the code for the TinyGo/Pico tutorials that appear on our YouTube [channel](https://www.youtube.com/channel/UChxDHx-FThGJscOn3ljTi6A). Please Subscribe to the channel, and Like and Comment on the videos. 4 | 5 | More in-depth explanations can be found on the [web site](https://pragmatik.tech/) 6 | 7 | -------------------------------------------------------------------------------- /blink/blink.go: -------------------------------------------------------------------------------- 1 | // blink.go 2 | 3 | package main 4 | 5 | import ( 6 | "machine" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | led := machine.LED 12 | led.Configure(machine.PinConfig{ 13 | Mode: machine.PinOutput, 14 | }) 15 | 16 | for { 17 | led.High() 18 | time.Sleep(500 * time.Millisecond) 19 | led.Low() 20 | time.Sleep(500 * time.Millisecond) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /blink/go.mod: -------------------------------------------------------------------------------- 1 | module pragmatik.tech/blink 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /channels/channels.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | const ( 10 | yellowLed = machine.GP16 11 | greenLed = machine.GP15 12 | ) 13 | 14 | func configure() { 15 | yellowLed.Configure(machine.PinConfig{Mode: machine.PinOutput}) 16 | greenLed.Configure(machine.PinConfig{Mode: machine.PinOutput}) 17 | } 18 | 19 | // Blinks an LED twice a second for a specified number of times. 20 | func blink(p machine.Pin, n int) { 21 | for i := 0; i < n; i++ { 22 | p.High() 23 | time.Sleep(250 * time.Millisecond) 24 | p.Low() 25 | time.Sleep(250 * time.Millisecond) 26 | } 27 | } 28 | 29 | // This goroutine blinks the green LED `numBlinks` times, where 30 | // numBlinks is specified by the message it receives via the channel. 31 | func blinkGreen(c chan int) { 32 | for { 33 | // block until you receive a value via the channel 34 | numBlinks := <-c 35 | 36 | // then, blink the green LED that many times 37 | blink(greenLed, numBlinks) 38 | 39 | // return a random value to the `main` goroutine so that it blinks 40 | // the yellow LED as many times as this random value. 41 | numBlinks = rand.Intn(5-1) + 1 42 | c <- numBlinks 43 | } 44 | } 45 | 46 | func main() { 47 | // Create an unbuffered channel of ints. 48 | c := make(chan int) 49 | 50 | // Initialize the random seed 51 | rand.Seed(time.Now().UnixNano()) 52 | 53 | // Generate a random number between 1 and 5 54 | n := rand.Intn(5-1) + 1 55 | 56 | configure() 57 | 58 | // Start the blinkGreen goroutine 59 | go blinkGreen(c) 60 | 61 | for { 62 | // First blink the yellow LED `n` times 63 | blink(yellowLed, n) 64 | 65 | // then, generate a random number between 1 and 5 66 | n = rand.Intn(5-1) + 1 67 | 68 | // send that random number via the channel to `blinkGreen` 69 | // so that it blinks the green LED that many times 70 | c <- n 71 | 72 | // wait for `blinkGreen` to return a random number to you 73 | n = <-c 74 | } // and repeat indefinitely 75 | } 76 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module tinygo-tutorial 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /gpio-interrupts/go.mod: -------------------------------------------------------------------------------- 1 | module gpio-interrupts 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /gpio-interrupts/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | // Initialize the white LED on GPIO16 10 | led := machine.GP16 11 | led.Configure(machine.PinConfig{ 12 | Mode: machine.PinOutput, 13 | }) 14 | 15 | // Initialize the green LED on GPIO15 16 | led2 := machine.GP15 17 | led2.Configure(machine.PinConfig{ 18 | Mode: machine.PinOutput, 19 | }) 20 | 21 | // Initialize the button on GPIO17 and set its internal pull-up resistor. 22 | btn := machine.GP17 23 | btn.Configure(machine.PinConfig{ 24 | Mode: machine.PinInputPullup, 25 | }) 26 | 27 | // Register the interrupt service routine (ISR) to set the status of the 28 | // white LED to the *inverse* of the status of the pushbutton pin. 29 | btn.SetInterrupt(machine.PinFalling|machine.PinRising, 30 | func(p machine.Pin) { 31 | led.Set(!p.Get()) 32 | }) 33 | 34 | // Finally, just loop indefinitely while blinking the green LED. 35 | for { 36 | led2.High() 37 | time.Sleep(500 * time.Millisecond) 38 | led2.Low() 39 | time.Sleep(500 * time.Millisecond) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /images/pragmatik-logo-1852x484.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pragmatiktech/tinygo-tutorial/a78bc4dedbd78e5cf2760d17359784c0520ac847/images/pragmatik-logo-1852x484.png -------------------------------------------------------------------------------- /images/pragmatik-logo-200x53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pragmatiktech/tinygo-tutorial/a78bc4dedbd78e5cf2760d17359784c0520ac847/images/pragmatik-logo-200x53.png -------------------------------------------------------------------------------- /more-interrupts/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | ) 7 | 8 | const ( 9 | led = machine.GP16 10 | led2 = machine.GP15 11 | btn = machine.GP17 12 | ) 13 | 14 | // This function configures the GPIO peripherals, two LEDs as output, and 15 | // the push button as an input with a pullup resistor using the internal pullup. 16 | func configure() { 17 | led.Configure(machine.PinConfig{ 18 | Mode: machine.PinOutput, 19 | }) 20 | led2.Configure(machine.PinConfig{ 21 | Mode: machine.PinOutput, 22 | }) 23 | btn.Configure(machine.PinConfig{ 24 | Mode: machine.PinInputPullup, 25 | }) 26 | } 27 | 28 | // isr is the function that "services" the interrupt, 29 | // or is the "callback" function when an interrupt is fired on the pin connected 30 | // to the push button. In this case, the function merely sets the LED to the 31 | // inverse of the push button state. 32 | func isr(p machine.Pin) { 33 | // disable the interrupt service routine since that's a good thing to do. 34 | btn.SetInterrupt(machine.PinFalling|machine.PinRising, nil) 35 | 36 | led.Set(!p.Get()) // this hasn't changed from our original program. 37 | 38 | // simulate a long-running process 39 | for i := 0; i < 10000; i++ { 40 | print(i) 41 | } 42 | 43 | // re-enable the interrupt service routine. 44 | btn.SetInterrupt(machine.PinFalling|machine.PinRising, isr) 45 | } 46 | 47 | func main() { 48 | // Configure the pins. 49 | configure() 50 | 51 | // Register the interrupt service routine (ISR) 52 | btn.SetInterrupt(machine.PinFalling|machine.PinRising, isr) 53 | 54 | // Finally, just loop indefinitely while blinking the green LED. 55 | for { 56 | led2.High() 57 | time.Sleep(500 * time.Millisecond) 58 | led2.Low() 59 | time.Sleep(500 * time.Millisecond) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pwm-blink/pwm-blink.go: -------------------------------------------------------------------------------- 1 | package pwm_blink 2 | -------------------------------------------------------------------------------- /slides/pragmatik.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * @theme pragmatik 3 | * @author Charath Ranganathan 4 | * 5 | * @auto-scaling true 6 | * @size 16:9 1280px 720px 7 | * @size 4:3 960px 720px 8 | */ 9 | @import url("https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github.min.css"); 10 | @import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap"); 11 | @import-theme "gaia"; 12 | /* Variables */ 13 | h1 { 14 | color: #0e6572; 15 | font-family: "Open Sans", sans-serif; 16 | font-weight: 600; 17 | } 18 | 19 | h2 { 20 | color: #99004C; 21 | font-weight: 600; 22 | } 23 | 24 | code { 25 | background-color: #fff; 26 | color: #2A2A2A; 27 | font-size: 1em; 28 | margin-left: 0px; 29 | padding-left: 0px; 30 | font-family: "Jetbrains Mono", monospace; 31 | } 32 | 33 | pre > code { 34 | font-family: "Jetbrains Mono", monospace; 35 | font-size: 0.85em; 36 | background-color: #fff; 37 | color: #2A2A2A; 38 | line-height: 1em; 39 | box-sizing: border-box; 40 | margin: 0; 41 | min-width: 100%; 42 | padding: 0.5em; 43 | } 44 | 45 | section { 46 | background-color: #fff; 47 | color: #2A2A2A; 48 | font-family: "Roboto", sans-serif; 49 | padding: 50px; 50 | } 51 | section .hljs { 52 | background: white; 53 | color: black; 54 | } 55 | section .hljs-comment, 56 | section .hljs-quote { 57 | color: #800; 58 | } 59 | section .hljs-keyword, 60 | section .hljs-selector-tag, 61 | section .hljs-section, 62 | section .hljs-title, 63 | section .hljs-name { 64 | color: #008; 65 | } 66 | section .hljs-variable, 67 | section .hljs-template-variable { 68 | color: #660; 69 | } 70 | section .hljs-string, 71 | section .hljs-selector-attr, 72 | section .hljs-selector-pseudo, 73 | section .hljs-regexp { 74 | color: #080; 75 | } 76 | section .hljs-literal, 77 | section .hljs-symbol, 78 | section .hljs-bullet, 79 | section .hljs-meta, 80 | section .hljs-number, 81 | section .hljs-link { 82 | color: #066; 83 | } 84 | section .hljs-title, 85 | section .hljs-doctag, 86 | section .hljs-type, 87 | section .hljs-attr, 88 | section .hljs-built_in, 89 | section .hljs-params { 90 | color: #606; 91 | } 92 | section .hljs-attribute, 93 | section .hljs-subst { 94 | color: #000; 95 | } 96 | section .hljs-formula { 97 | background-color: #eee; 98 | font-style: italic; 99 | } 100 | section .hljs-selector-id, 101 | section .hljs-selector-class { 102 | color: #9B703F; 103 | } 104 | section .hljs-addition { 105 | background-color: #baeeba; 106 | } 107 | section .hljs-deletion { 108 | background-color: #ffc8bd; 109 | } 110 | section .hljs-doctag, 111 | section .hljs-strong { 112 | font-weight: bold; 113 | } 114 | section .hljs-emphasis { 115 | font-style: italic; 116 | }/*# sourceMappingURL=pragmatik.css.map */ -------------------------------------------------------------------------------- /slides/pragmatik.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["pragmatik.scss","pragmatik.css"],"names":[],"mappings":"AAAA;;;;;;;CAAA;AASQ,8FAAA;AACA,oRAAA;AACR,oBAAA;AAEA,cAAA;AAMA;EACE,cANS;EAOT,oCAAA;EACA,gBAAA;ACNF;;ADSA;EACE,cAXS;EAYT,gBAAA;ACNF;;ADSA;EACE,sBAfS;EAgBT,cAfS;EAgBT,cAAA;EACA,gBAAA;EACA,iBAAA;EACA,wCAAA;ACNF;;ADSA;EACE,wCAAA;EACA,iBAAA;EACA,sBA1BS;EA2BT,cA1BS;EA2BT,gBAAA;EACA,sBAAA;EACA,SAAA;EACA,eAAA;EACA,cAAA;ACNF;;ADSA;EACE,sBApCS;EAqCT,cApCS;EAqCT,iCAAA;EACA,aAAA;ACNF;ADSE;EACE,iBAAA;EACA,YAAA;ACPJ;ADUE;;EAEE,WAAA;ACRJ;ADWE;;;;;EAKE,WAAA;ACTJ;ADYE;;EAEE,WAAA;ACVJ;ADaE;;;;EAIE,WAAA;ACXJ;ADcE;;;;;;EAME,WAAA;ACZJ;ADeE;;;;;;EAME,WAAA;ACbJ;ADgBE;;EAEE,WAAA;ACdJ;ADiBE;EACE,sBAAA;EACA,kBAAA;ACfJ;ADkBE;;EAEE,cAAA;AChBJ;ADmBE;EACE,yBAAA;ACjBJ;ADoBE;EACE,yBAAA;AClBJ;ADqBE;;EAEE,iBAAA;ACnBJ;ADsBE;EACE,kBAAA;ACpBJ","file":"pragmatik.css"} -------------------------------------------------------------------------------- /slides/pragmatik.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * @theme pragmatik 3 | * @author Charath Ranganathan 4 | * 5 | * @auto-scaling true 6 | * @size 16:9 1280px 720px 7 | * @size 4:3 960px 720px 8 | */ 9 | 10 | @import url('https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github.min.css'); 11 | @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Open+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap'); 12 | @import-theme "gaia"; 13 | 14 | /* Variables */ 15 | $h1-color: #0e6572; 16 | $h2-color: #99004C; 17 | $bg-color: #fff; 18 | $fg-color: #2A2A2A; 19 | 20 | h1 { 21 | color: $h1-color; 22 | font-family: "Open Sans", sans-serif; 23 | font-weight: 600; 24 | } 25 | 26 | h2 { 27 | color: $h2-color; 28 | font-weight: 600; 29 | } 30 | 31 | code { 32 | background-color: $bg-color; 33 | color: $fg-color; 34 | font-size: 1em; 35 | margin-left: 0px; 36 | padding-left: 0px; 37 | font-family: "Jetbrains Mono", monospace; 38 | } 39 | 40 | pre > code { 41 | font-family: 'Jetbrains Mono', monospace; 42 | font-size: 0.85em; 43 | background-color: $bg-color; 44 | color: $fg-color; 45 | line-height: 1.0em; 46 | box-sizing: border-box; 47 | margin: 0; 48 | min-width: 100%; 49 | padding: 0.5em; 50 | } 51 | 52 | section { 53 | background-color: $bg-color; 54 | color: $fg-color; 55 | font-family: "Roboto", sans-serif; 56 | padding: 50px; 57 | 58 | // hl.js style GoogleCode 59 | .hljs { 60 | background: white; 61 | color: black; 62 | } 63 | 64 | .hljs-comment, 65 | .hljs-quote { 66 | color: #800; 67 | } 68 | 69 | .hljs-keyword, 70 | .hljs-selector-tag, 71 | .hljs-section, 72 | .hljs-title, 73 | .hljs-name { 74 | color: #008; 75 | } 76 | 77 | .hljs-variable, 78 | .hljs-template-variable { 79 | color: #660; 80 | } 81 | 82 | .hljs-string, 83 | .hljs-selector-attr, 84 | .hljs-selector-pseudo, 85 | .hljs-regexp { 86 | color: #080; 87 | } 88 | 89 | .hljs-literal, 90 | .hljs-symbol, 91 | .hljs-bullet, 92 | .hljs-meta, 93 | .hljs-number, 94 | .hljs-link { 95 | color: #066; 96 | } 97 | 98 | .hljs-title, 99 | .hljs-doctag, 100 | .hljs-type, 101 | .hljs-attr, 102 | .hljs-built_in, 103 | .hljs-params { 104 | color: #606; 105 | } 106 | 107 | .hljs-attribute, 108 | .hljs-subst { 109 | color: #000; 110 | } 111 | 112 | .hljs-formula { 113 | background-color: #eee; 114 | font-style: italic; 115 | } 116 | 117 | .hljs-selector-id, 118 | .hljs-selector-class { 119 | color: #9B703F 120 | } 121 | 122 | .hljs-addition { 123 | background-color: #baeeba; 124 | } 125 | 126 | .hljs-deletion { 127 | background-color: #ffc8bd; 128 | } 129 | 130 | .hljs-doctag, 131 | .hljs-strong { 132 | font-weight: bold; 133 | } 134 | 135 | .hljs-emphasis { 136 | font-style: italic; 137 | } 138 | // end hl.js style 139 | } -------------------------------------------------------------------------------- /spi_74hc595/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | ) 7 | 8 | const ( 9 | rclk = machine.GP20 10 | ) 11 | 12 | var sr = machine.SPI0 13 | 14 | func write(val int) { 15 | rclk.Low() 16 | sr.Tx([]byte{byte(val)}, nil) 17 | rclk.High() 18 | rclk.Low() 19 | } 20 | 21 | func configure() { 22 | sr.Configure(machine.SPIConfig{ 23 | Frequency: 100000, 24 | LSBFirst: false, 25 | Mode: 1, 26 | DataBits: 8, 27 | SCK: machine.GP18, 28 | SDO: machine.GP19, 29 | }) 30 | rclk.Configure(machine.PinConfig{ 31 | Mode: machine.PinOutput, 32 | }) 33 | rclk.Low() 34 | } 35 | 36 | func main() { 37 | configure() 38 | for i := 0; i < 256; i++ { 39 | write(i) 40 | time.Sleep(100 * time.Millisecond) 41 | } 42 | time.Sleep(time.Second) 43 | write(0) 44 | } 45 | --------------------------------------------------------------------------------