Let's start with the result:
You can see a Teensy 3.1 and a dipsy connected to it. The Teensy configures the Dipsy and then sends single bytes over the SPI to set LED brightness. Here's the teensy code:
#include <SPI.h>
#include <dipsydownloader.h>
extern const uint8_t dipsy_bitmap[];
extern const uint16_t dipsy_bitmap_size;
static const uint8_t DIPSY_CRESETB = 0;
static const uint8_t DIPSY_CDONE = 1;
static const uint8_t DIPSY_SS = 2;
void setup() {
while(!Serial.available());
while(Serial.available()) Serial.read();
SPI.begin();
dipsy::ArrayConfig config(dipsy_bitmap_size, dipsy_bitmap);
if (dipsy::configure(DIPSY_CRESETB, DIPSY_CDONE, DIPSY_SS, SPI, config))
{
Serial.print("config done");
}
else
{
Serial.print("config error");
while(1);
}
SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE3));
pinMode(DIPSY_SS, OUTPUT);
digitalWriteFast(DIPSY_SS, 1);
delay(10);
}
void loop() {
uint8_t val = 0;
digitalWriteFast(DIPSY_SS, 0);
SPI.transfer(val);
digitalWriteFast(DIPSY_SS, 1);
Serial.println(val);
delay(1000);
val = 127;
digitalWriteFast(DIPSY_SS, 0);
SPI.transfer(val);
digitalWriteFast(DIPSY_SS, 1);
Serial.println(val);
delay(1000);
val = 255;
digitalWriteFast(DIPSY_SS, 0);
SPI.transfer(val);
digitalWriteFast(DIPSY_SS, 1);
Serial.println(val);
delay(1000);
}
After configuring the dipsy, the Teensy enters a single loop where it selects the slave and sends a single byte before the slave is deselected again. The dipsy code is probably more interesting.The top level (top.v):
module top( input SCK, input MOSI, input CS, output LED ); wire SYSCLK; // hard IP, 84 MHz oscillator divided down to 6 MHz SB_HFOSC #(.CLKHF_DIV("0b11")) osc( .CLKHFEN(1'b1), .CLKHFPU(1'b1), .CLKHF(SYSCLK) ) /* synthesis ROUTE_THROUGH_FABRIC= 0 */; wire[7:0] DUTY_CYCLE; simple_spi_8bit_mode3 spi( .SCK(SCK), .MOSI(MOSI), .CS(CS), .DOUT(DUTY_CYCLE) ); // connects PWM generator to LED driver wire PWM; simple_pwm pwm( .CLK(SYSCLK), .DUTY_CYCLE(DUTY_CYCLE), .PWM(PWM) ); // again hard IP, constant current driver with pwm input SB_RGBA_DRV RGBA_DRIVER ( .CURREN(1'b1), .RGBLEDEN(1'b1), .RGB0PWM(PWM), .RGB1PWM(1'b0), .RGB2PWM(1'b0), .RGB0(LED) ); defparam RGBA_DRIVER.CURRENT_MODE = "0b0"; defparam RGBA_DRIVER.RGB0_CURRENT = "0b1"; defparam RGBA_DRIVER.RGB1_CURRENT = "0b1"; defparam RGBA_DRIVER.RGB2_CURRENT = "0b1"; endmoduleHere we have the modules I/O (SPI SCK, MOSI, CS and PWM out) and some submodules:
- an internal oscillator is used to generate a 6 MHz clock for the PWM module
- a simple SPI slave is connected to the SPI inputs and receives in mode 3
- the pwm module receives the desired duty cycle from the SPI slave
- the pwm module's output is fed into the LED driver, which is again one of dipsy's hard IPs.
The SPI is a shift register with a latch (simple_spi_8bit_mode3.v):
module simple_spi_8bit_mode3( input SCK, input MOSI, output MISO, input CS, output reg[7:0] DOUT ); reg[7:0] shiftreg = 0; assign MISO = CS ? 1'bz : shiftreg[7]; always @(posedge CS) begin DOUT = shiftreg; end always @(posedge SCK) if(!CS) begin shiftreg = {shiftreg[6:0],MOSI}; end endmoduleAnd the PWM is a counter and a comparator. It latches when it rolls over to zero to avoid glitches (simple_pwm.v):
module simple_pwm ( CLK, DUTY_CYCLE, PWM ); parameter BITS = 8; parameter TOP = 2**BITS-1; input CLK; input[BITS-1:0] DUTY_CYCLE; output PWM; reg[BITS-1:0] count = TOP; reg[BITS-1:0] duty_cycle_i = 0; assign PWM = (count < duty_cycle_i) ? 1'b1:1'b0; always @(posedge CLK) begin count = count + "1"; if(count == (TOP)) begin count = 0; duty_cycle_i = DUTY_CYCLE; end end endmodulePin assignments:
###IOSet List 3 set_io CS D1 set_io MOSI D2 set_io SCK C1 -io_std SB_LVCMOS -pullup noI'm not really sure how these *should* look, but these settings worked for me.
Now this might not be overly impressive, but it shows that dipsy can be used to create custom peripherals. This example used 43 of 1248 logic cells.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Cool :)
Are you sure? yes | no