-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(merge, #7): Initial MCP3008 support
- Loading branch information
Showing
12 changed files
with
632 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "mcp3008_hardware.h" | ||
|
||
spi_dual_inst mcp3008_init_hardware(spi_inst_t *spi, uint baudrate, spi_pinout_t *pinout) | ||
{ | ||
spi_dual_inst inst = { | ||
.spi_hw = spi, | ||
//.baudrate = baudrate, | ||
.pinout = pinout, | ||
.isHw = true, | ||
}; | ||
|
||
// Init SPIx at specified baudrate | ||
inst.baudrate = spi_init(inst.spi_hw, baudrate); | ||
|
||
// Assign SPI functions to pins | ||
gpio_set_function(inst.pinout->miso, GPIO_FUNC_SPI); | ||
gpio_set_function(inst.pinout->sck, GPIO_FUNC_SPI); | ||
gpio_set_function(inst.pinout->mosi, GPIO_FUNC_SPI); | ||
// gpio_set_function(5, GPIO_FUNC_SPI); | ||
|
||
gpio_init(inst.pinout->csn); | ||
gpio_set_dir(inst.pinout->csn, GPIO_OUT); | ||
gpio_put(inst.pinout->csn, 1); | ||
|
||
// Create an input buffer and initialise it to zero. | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
inst.input_buffer[i] = 0; | ||
} | ||
|
||
return inst; | ||
} | ||
|
||
// -- Internal function to handle sending data -- | ||
uint16_t mcp3008_read_hardware(spi_dual_inst *inst, uint8_t channel, bool differential) | ||
{ | ||
if (inst->isHw) | ||
{ | ||
// Create a buffer to sent to the device initialised to zero | ||
uint8_t output_buffer[BUF_LEN]; | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
output_buffer[i] = 0; | ||
} | ||
|
||
// Byte 1, leading zeros ending with a start bit | ||
output_buffer[0] = 0x01; | ||
|
||
// Byte 2 | ||
// Bit 1, differential signal selection | ||
// Bits 2-4 channel select | ||
// Rest of buffer ignored | ||
output_buffer[1] = ((differential ? 0 : 1) << 7 | channel << 4); | ||
|
||
// temp | ||
uint8_t input_buffer[BUF_LEN]; | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
input_buffer[i] = 0; | ||
} | ||
|
||
// Send the SPI command | ||
|
||
gpio_put(inst->pinout->csn, 0); | ||
__breakpoint(); | ||
spi_write_read_blocking(inst->spi_hw, output_buffer, input_buffer, BUF_LEN); | ||
gpio_put(inst->pinout->csn, 1); | ||
|
||
// Response | ||
// 13 bits garbage | ||
// 1 bit null (0) | ||
// data, ordered bits 9 to 0 | ||
// mask 0x07 last 3 bits | ||
// mask 0x03 last 2 bits | ||
// return (((uint16_t)(input_buffer[1] & 0x03)) << 8) | input_buffer[2]; | ||
return (((uint16_t)(input_buffer[1] & 0x03)) << 8) | input_buffer[2]; | ||
} | ||
else | ||
{ | ||
printf("\n(error) [mcp3008]: PIO instance attempted to call HW handler."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#ifndef HARDWARE_MCP3008_HARDWARE_H_ | ||
#define HARDWARE_MCP3008_HARDWARE_H_ | ||
|
||
#include "hardware/spi.h" | ||
|
||
#include "../pinout.h" | ||
#include "../mcp3008.h" | ||
|
||
spi_dual_inst mcp3008_init_hardware(spi_inst_t *spi, uint baudrate, spi_pinout_t *pinout); | ||
uint16_t mcp3008_read_hardware(spi_dual_inst *inst, uint8_t channel, bool differential); | ||
|
||
#endif /* HARDWARE_MCP3008_HARDWARE_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
// Accompanying header file | ||
#include "mcp3008.h" | ||
|
||
// PIO and hardware mcp3008 functions | ||
#include "./hardware/mcp3008_hardware.h" | ||
#include "./pio/mcp3008_pio.h" | ||
|
||
spi_dual_inst mcp3008_init(spi_pinout_t *pinout, bool IshwInstance, bool instance) | ||
{ | ||
if (IshwInstance) | ||
{ | ||
// Init hardware | ||
|
||
// Determine weather to use spi0 or spi1 | ||
// If 0 / false, SPI 0. | ||
// If 1 / true, SPI 1. | ||
spi_inst_t *spi = (instance ? spi1 : spi0); | ||
|
||
return mcp3008_init_hardware(spi, SPI_CLOCK_SPEED, pinout); | ||
} | ||
else | ||
{ | ||
// Init PIO | ||
|
||
// Determine weather to use pio0 or pio1 | ||
// If 0 / false, PIO 0. | ||
// If 1 / true, PIO 1. | ||
PIO pio = (instance ? pio1 : pio0); | ||
|
||
return mcp3008_init_pio(pio, SPI_CLOCK_SPEED, pinout); | ||
} | ||
} | ||
|
||
uint16_t mcp3008_read(spi_dual_inst *inst, uint8_t channel, bool differential) | ||
{ | ||
if (inst->isHw) | ||
{ | ||
return mcp3008_read_hardware(inst, channel, differential); | ||
} | ||
else | ||
{ | ||
return mcp3008_read_pio(inst, channel, differential); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#ifndef MCP3008_MCP3008_H_ | ||
#define MCP3008_MCP3008_H_ | ||
|
||
#include "hardware/spi.h" | ||
#include "pio/pio_spi.h" | ||
|
||
#include "pinout.h" | ||
|
||
// TODO: can definitely get away with a smaller size | ||
#define BUF_LEN 3 | ||
|
||
// Datasheet specifies 3.6MHz max | ||
// 8MHz probably works though | ||
// See https://github.com/adafruit/Adafruit_MCP3008/issues/9 | ||
#define SPI_CLOCK_SPEED 3600000 // 3.6MHz | ||
|
||
typedef struct | ||
{ | ||
spi_inst_t *spi_hw; | ||
pio_spi_inst_t spi_pio; // if *spi_pio, read/write operations hang. | ||
uint baudrate; | ||
spi_pinout_t *pinout; | ||
uint8_t input_buffer[BUF_LEN]; | ||
bool isHw; | ||
} spi_dual_inst; | ||
|
||
// Function definitions | ||
spi_dual_inst mcp3008_init(spi_pinout_t *pinout, bool IshwInstance, bool instance); | ||
uint16_t mcp3008_read(spi_dual_inst *inst, uint8_t channel, bool differential); | ||
|
||
#endif /* MCP3008_MCP3008_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#ifndef MCP3008_PINOUT_H_ | ||
#define MCP3008_PINOUT_H_ | ||
|
||
typedef struct TU_ATTR_PACKED | ||
{ | ||
int miso; | ||
int mosi; | ||
int sck; | ||
int csn; | ||
} spi_pinout_t; | ||
|
||
#endif /* MCP3008_PINOUT_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "mcp3008_pio.h" | ||
|
||
// clk_sys enum | ||
#include "hardware/clocks.h" | ||
|
||
spi_dual_inst mcp3008_init_pio(PIO pio, uint baudrate, spi_pinout_t *pinout) | ||
{ | ||
pio_spi_inst_t spi = { | ||
.pio = pio, // pio to use (pio0, pio1) | ||
.sm = pio_claim_unused_sm(pio, true) // claim first free state machine | ||
}; | ||
|
||
// Based on: https://medium.com/geekculture/raspberry-pico-programming-with-pio-state-machines-e4610e6b0f29 | ||
// *Should* make the spi clock speed correct. | ||
float clock_divider = (float)clock_get_hz(clk_sys) / SPI_CLOCK_SPEED; | ||
// float clkdiv = 31.25f; // 1 MHz @ 125 clk_sys | ||
|
||
uint cpha0_prog_offs = pio_add_program(spi.pio, &spi_cpha0_program); | ||
|
||
pio_spi_init( | ||
spi.pio, // pio | ||
spi.sm, // state machine (num) | ||
cpha0_prog_offs, // program offsets | ||
8, // number of bits per SPI frame | ||
clock_divider, // Clock divider | ||
0, // cpha | ||
1, // cpol | ||
pinout->sck, // SCK pin, | ||
pinout->mosi, // MOSI pin | ||
pinout->miso // MISO pin | ||
); | ||
|
||
// Setup CS pin | ||
gpio_init(pinout->csn); | ||
gpio_set_dir(pinout->csn, GPIO_OUT); | ||
gpio_put(pinout->csn, 1); | ||
|
||
spi_dual_inst inst = { | ||
.spi_pio = spi, | ||
.baudrate = baudrate, | ||
.pinout = pinout, | ||
.isHw = false, | ||
}; | ||
|
||
// Create an input buffer and initialise it to zero. | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
inst.input_buffer[i] = 0; | ||
} | ||
|
||
return inst; | ||
} | ||
|
||
uint16_t mcp3008_read_pio(spi_dual_inst *inst, uint8_t channel, bool differential) | ||
{ | ||
if (!inst->isHw) | ||
{ | ||
|
||
// Create a buffer to sent to the device initialised to zero | ||
uint8_t output_buffer[BUF_LEN]; | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
output_buffer[i] = 0; | ||
} | ||
|
||
// Byte 1, leading zeros ending with a start bit | ||
output_buffer[0] = 0x01; | ||
|
||
// Byte 2 | ||
// Bit 1, differential signal selection | ||
// Bits 2-4 channel select | ||
// Rest of buffer ignored | ||
output_buffer[1] = ((differential ? 0 : 1) << 7 | channel << 4); | ||
|
||
// temp | ||
uint8_t input_buffer[BUF_LEN]; | ||
for (uint8_t i = 0; i < BUF_LEN; i++) | ||
{ | ||
input_buffer[i] = 0; | ||
} | ||
|
||
// Send SPI command | ||
gpio_put(inst->pinout->csn, 0); | ||
|
||
pio_spi_write8_read8_blocking(&(inst->spi_pio), output_buffer, input_buffer, BUF_LEN); | ||
gpio_put(inst->pinout->csn, 1); | ||
|
||
uint16_t data = (((uint16_t)(input_buffer[1] & 0x03)) << 8) | input_buffer[2]; | ||
|
||
return data; | ||
} | ||
else | ||
{ | ||
printf("\n(error): [mcp3008]: HW instance attempted to call PIO handler."); | ||
} | ||
} |
Oops, something went wrong.