mcp4451: Add initial support for programming the mcp4451 on lpc176x
Add support for programming smoothieboard current. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
cc6b416660
commit
d725160706
|
@ -424,6 +424,35 @@
|
|||
# default is to not scale the 'channel_x' parameters.
|
||||
|
||||
|
||||
# Statically configured MCP4451 digipot connected via I2C bus (one may
|
||||
# define any number of sections with an "mcp4451" prefix).
|
||||
#[mcp4451 my_digipot]
|
||||
#mcu: mcu
|
||||
# The name of the micro-controller that the MCP4451 chip is
|
||||
# connected to. The default is "mcu".
|
||||
#i2c_address:
|
||||
# The i2c address that the chip is using on the i2c bus. This
|
||||
# parameter must be provided.
|
||||
#wiper_0:
|
||||
#wiper_1:
|
||||
#wiper_2:
|
||||
#wiper_3:
|
||||
# The value to statically set the given MCP4451 "wiper" to. This is
|
||||
# typically set to a number between 0.0 and 1.0 with 1.0 being the
|
||||
# highest resistance and 0.0 being the lowest resistance. However,
|
||||
# the range may be changed with the 'scale' parameter (see
|
||||
# below). If a wiper is not specified then it is left unconfigured.
|
||||
#scale:
|
||||
# This parameter can be used to alter how the 'wiper_x' parameters
|
||||
# are interpreted. If provided, then the 'wiper_x' parameters should
|
||||
# be between 0.0 and 'scale'. This may be useful when the MCP4451 is
|
||||
# used to set stepper voltage references. The 'scale' can be set to
|
||||
# the equivalent stepper amperage if the MCP4451 were at its highest
|
||||
# resistance, and then the 'wiper_x' parameters can be specified
|
||||
# using the desired amperage value for the stepper. The default is
|
||||
# to not scale the 'wiper_x' parameters.
|
||||
|
||||
|
||||
# Configure a TMC2130 stepper motor driver via SPI bus. To use this
|
||||
# feature, define a config section with a "tmc2130" prefix followed by
|
||||
# the name of the corresponding stepper config section (for example,
|
||||
|
|
|
@ -85,3 +85,19 @@ max_z_accel: 100
|
|||
|
||||
[static_digital_output leds]
|
||||
pins: P1.18, P1.19, P1.20, P1.21, P4.28
|
||||
|
||||
[mcp4451 stepper_digipot1]
|
||||
i2c_address: 88
|
||||
# Scale the config so that values can be specified in amps.
|
||||
scale: 2.25
|
||||
# wiper 0 is X (aka alpha), 1 is Y, 2 is Z, 3 is E0
|
||||
wiper_0: 1.0
|
||||
wiper_1: 1.0
|
||||
wiper_2: 1.0
|
||||
wiper_3: 1.0
|
||||
|
||||
[mcp4451 stepper_digipot2]
|
||||
i2c_address: 90
|
||||
scale: 2.25
|
||||
# wiper 0 is E1
|
||||
wiper_0: 1.0
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# MCP4451 digipot code
|
||||
#
|
||||
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import mcu
|
||||
|
||||
WiperRegisters = [0x00, 0x01, 0x06, 0x07]
|
||||
|
||||
class mcp4451:
|
||||
def __init__(self, config):
|
||||
printer = config.get_printer()
|
||||
self.mcu = mcu.get_printer_mcu(printer, config.get('mcu', 'mcu'))
|
||||
self.i2c_addr = config.getint('i2c_address')
|
||||
scale = config.getfloat('scale', 1., above=0.)
|
||||
wipers = [None]*4
|
||||
for i in range(len(wipers)):
|
||||
val = config.getfloat('wiper_%d' % (i,), None,
|
||||
minval=0., maxval=scale)
|
||||
if val is not None:
|
||||
wipers[i] = int(val * 255. / scale + .5)
|
||||
self.add_config_cmd(0x04, 0xff)
|
||||
self.add_config_cmd(0x0a, 0xff)
|
||||
for reg, val in zip(WiperRegisters, wipers):
|
||||
if val is not None:
|
||||
self.add_config_cmd(reg, val)
|
||||
def add_config_cmd(self, reg, val):
|
||||
self.mcu.add_config_cmd("i2c_send data=%02x%02x%02x" % (
|
||||
self.i2c_addr, (reg << 4) | ((val >> 8) & 0x03), val), is_init=True)
|
||||
|
||||
def load_config_prefix(config):
|
||||
return mcp4451(config)
|
|
@ -13,7 +13,7 @@ CFLAGS_klipper.elf += -T $(OUT)LPC1768.ld
|
|||
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
|
||||
|
||||
# Add source files
|
||||
src-y += lpc176x/main.c lpc176x/timer.c lpc176x/gpio.c
|
||||
src-y += lpc176x/main.c lpc176x/timer.c lpc176x/gpio.c lpc176x/i2c.c
|
||||
src-y += generic/crc16_ccitt.c generic/alloc.c
|
||||
src-y += generic/armcm_irq.c generic/timer_irq.c
|
||||
src-y += ../lib/lpc176x/device/system_LPC17xx.c
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
// I2C functions on lpc176x
|
||||
//
|
||||
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "LPC17xx.h" // LPC_I2C1
|
||||
#include "board/misc.h" // timer_is_before
|
||||
#include "command.h" // DECL_COMMAND
|
||||
#include "internal.h" // gpio_peripheral
|
||||
#include "sched.h" // sched_shutdown
|
||||
|
||||
// i2c connection status flags
|
||||
enum {
|
||||
IF_START = 1<<5, IF_STOP = 1<<4, IF_IRQ = 1<<3, IF_ACK = 1<<2, IF_ENA = 1<<6
|
||||
};
|
||||
|
||||
static void
|
||||
i2c_init(void)
|
||||
{
|
||||
static int have_run_init;
|
||||
if (have_run_init)
|
||||
return;
|
||||
have_run_init = 1;
|
||||
|
||||
// Init i2c bus 1 pins
|
||||
gpio_peripheral(0, 0, 3, 0);
|
||||
gpio_peripheral(0, 1, 3, 0);
|
||||
|
||||
// Set 100Khz frequency
|
||||
uint32_t PCLK = SystemCoreClock / 4, pulse = PCLK / (100000 * 2);
|
||||
LPC_I2C1->I2SCLL = pulse;
|
||||
LPC_I2C1->I2SCLH = pulse;
|
||||
|
||||
// Enable interface
|
||||
LPC_I2C1->I2CONCLR = IF_START | IF_IRQ | IF_ACK | IF_ENA;
|
||||
LPC_I2C1->I2CONSET = IF_ENA;
|
||||
}
|
||||
|
||||
static void
|
||||
i2c_wait(uint32_t bit, uint32_t timeout)
|
||||
{
|
||||
for (;;) {
|
||||
uint32_t flags = LPC_I2C1->I2CONSET;
|
||||
if (flags & bit)
|
||||
break;
|
||||
if (!timer_is_before(timer_read_time(), timeout))
|
||||
shutdown("i2c timeout");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i2c_start(uint32_t timeout)
|
||||
{
|
||||
LPC_I2C1->I2CONCLR = IF_ACK | IF_IRQ | IF_START;
|
||||
LPC_I2C1->I2CONSET = IF_ACK | IF_START;
|
||||
i2c_wait(IF_IRQ, timeout);
|
||||
uint32_t status = LPC_I2C1->I2STAT;
|
||||
if (status != 0x10 && status != 0x08)
|
||||
shutdown("Failed to send i2c start");
|
||||
LPC_I2C1->I2CONCLR = IF_START;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
i2c_send_byte(uint8_t b, uint32_t timeout)
|
||||
{
|
||||
LPC_I2C1->I2DAT = b;
|
||||
LPC_I2C1->I2CONCLR = IF_IRQ;
|
||||
i2c_wait(IF_IRQ, timeout);
|
||||
return LPC_I2C1->I2STAT;
|
||||
}
|
||||
|
||||
static void
|
||||
i2c_stop(uint32_t timeout)
|
||||
{
|
||||
LPC_I2C1->I2CONSET = IF_STOP;
|
||||
LPC_I2C1->I2CONCLR = IF_IRQ;
|
||||
i2c_wait(IF_STOP, timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
i2c_send(uint8_t *data, int data_len)
|
||||
{
|
||||
i2c_init();
|
||||
uint32_t timeout = timer_read_time() + timer_from_us(5000);
|
||||
|
||||
i2c_start(timeout);
|
||||
while (data_len--)
|
||||
i2c_send_byte(*data++, timeout);
|
||||
i2c_stop(timeout);
|
||||
}
|
||||
|
||||
// This provides just enough functionality to program an MCP4451 chip
|
||||
void
|
||||
command_i2c_send(uint32_t *args)
|
||||
{
|
||||
uint8_t data_len = args[0], *data = (void*)(size_t)args[1];
|
||||
i2c_send(data, data_len);
|
||||
}
|
||||
DECL_COMMAND(command_i2c_send, "i2c_send data=%*s");
|
Loading…
Reference in New Issue