Friday, July 24, 2015

flashLow.cpp/h

This is the low level flash driver. It has some stuff at the top of the cpp file that lets me see the pins states. I originally planned to use the Arduino LED blinking to know what was going on. The use of the serial port is much better.

Right now the diagnostic code is made of functions living in the file aren't part of the class. I'll change that going forward, or I'll remove it.

But, for now, the code seems to work.

       
#ifndef INCLUDE_FLASHLOW
#define INCLUDE_FLASHLOW
#include <Arduino.h>

class FlashLow
{
public:
    FlashLow();

    // Setsw the input/output pin mode
    void EnablePins(bool enable);

    // Resets the CPLD
    bool Reset();

    // Write data to *ptr.
    // NOTE: This is a NOT toggle bit operation, just sends data to *ptr
    // returns true if successful
    void Write(long ptr, byte data);

    // Read data at *ptr into *pData
    // returns true if successful
    void Read(long, byte* pData);

    // Force update of all address bits
    void UpdateAddress(long addr);

    // Update address bits only on parts that are different
    void UpdateAddressDiff(long addr);

    // Update address bits 3:0
    void UpdateAddress_3_0(long addr);

    // Update address bits 7:4
    void UpdateAddress_7_4(long addr);

    // Update address bits 17:8
    void UpdateAddress_17_8(long addr);

    // Update chip control where bits 3-0 are drive, CS*, WR*, and RD*
    void UpdateChip(int chip);

    // Update the CTRL register that tells which register to pulse data in and out
    void UpdateCtrl(int ctrl);

    // Swaps a data byte on Din/Dout
    byte ReadWrite(byte data);

    // Pulse CLK high and low
    void PulseClk();

    // Pulse nCTRL low and high
    void PulseCtrl();

    // Control pins directly
    void DirectWrite(bool enable, bool clk, bool din, bool ctrl);
    void DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl);

    // Reads until the toggle bits stop toggling
    // Returns true if the read data matches expected
    // Use expected of 0xff for erase operations
    bool Toggle(byte expected);

    // Send CPLD reset sequence
    void ResetSequence();

private:
    // Update an arbitrary part of the address bits
    void UpdateAddress_start_end(long addr, int startBit, int endBit);

    int m_lastAddr;

public:
    static const int PIN_nCTRL = 
    static const int PIN_Dout = 3;
    static const int PIN_Din = 4;
    static const int PIN_CLK = 5;
    static const int PIN_ENABLE = 6;
};

#endif

Here is the cpp part:
       
#include "flashLow.h"

//#define SUPER_SLO_MO() delay(1000)
#define SUPER_SLO_MO() SendOutPins()

void SendOutPins()
{
    byte progress[10] = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    progress[1] =
        (digitalRead(FlashLow::PIN_ENABLE) ? 0x01 : 0) |
        (digitalRead(FlashLow::PIN_nCTRL) ? 0x02 : 0) |
        (digitalRead(FlashLow::PIN_CLK) ? 0x04 : 0) |
        (digitalRead(FlashLow::PIN_Din) ? 0x08 : 0) |
        (digitalRead(FlashLow::PIN_Dout) ? 0x10 : 0);
    Serial.write(progress, 10);

    delay(250);
}

void BlinkOutPins()
{
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);

    if (digitalRead(FlashLow::PIN_ENABLE))
    {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        delay(500);
    }
    else
    {
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
    }

    delay(1000);
    if (digitalRead(FlashLow::PIN_nCTRL))
    {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        delay(500);
    }
    else
    {
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
    }

    delay(1000);
    if (digitalRead(FlashLow::PIN_CLK))
    {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        delay(500);
    }
    else
    {
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
    }

    delay(1000);
    if (digitalRead(FlashLow::PIN_Din))
    {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        delay(500);
    }
    else
    {
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
    }

    delay(1000);
    if (digitalRead(FlashLow::PIN_Dout))
    {
        digitalWrite(13, HIGH);
        delay(500);
        digitalWrite(13, LOW);
        delay(500);
    }
    else
    {
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
        digitalWrite(13, HIGH);
        delay(250);
        digitalWrite(13, LOW);
        delay(250);
    }

    delay(1000);
}

FlashLow::FlashLow()
{
    m_lastAddr = -1;
}

void FlashLow::EnablePins(bool enable)
{
    if (enable)
    {
        pinMode(PIN_ENABLE, OUTPUT);
        pinMode(PIN_nCTRL, OUTPUT);
        pinMode(PIN_Dout, INPUT);
        pinMode(PIN_Din, OUTPUT);
        pinMode(PIN_CLK, OUTPUT);
    }
    else
    {
        pinMode(PIN_ENABLE, INPUT_PULLUP);
        pinMode(PIN_nCTRL, INPUT_PULLUP);
        pinMode(PIN_Dout, INPUT);
        pinMode(PIN_Din, INPUT_PULLUP);
        pinMode(PIN_CLK, INPUT_PULLUP);
    }

}

void FlashLow::Write(long addr, byte data)
{
    UpdateAddressDiff(addr);
    ReadWrite(data);

    UpdateChip(0x1); // drive, CS, WR
    UpdateChip(0x3); // drive, CS
    UpdateChip(0xf); // done
}

void FlashLow::Read(long addr, byte* pData)
{
    UpdateAddressDiff(addr);
    *pData = ReadWrite(0);
}

void FlashLow::UpdateAddressDiff(long addr)
{
    if (m_lastAddr == -1)
    {
        UpdateAddress(addr);
    }
    else
    {
        long diffs = (addr ^ m_lastAddr);
        if ((diffs & 0x0000f) != 0)
        {
            UpdateAddress_3_0(addr);
        }
        if ((diffs & 0x000f0) != 0)
        {
            UpdateAddress_7_4(addr);
        }
        if ((diffs & 0xfff00) != 0)
        {
            UpdateAddress_17_8(addr);
        }

        m_lastAddr = addr;
    }
}

void FlashLow::UpdateAddress(long addr)
{
    UpdateAddress_3_0(addr);
    UpdateAddress_7_4(addr);
    UpdateAddress_17_8(addr);
    m_lastAddr = addr;
}

void FlashLow::UpdateAddress_start_end(long addr, int endBit, int startBit)
{
    int i;
    for (i = startBit; i <= endBit; ++i)
    {
        long mask = 1L << i;
        m_lastAddr &= ~mask;
        m_lastAddr |= (mask & addr);
        digitalWrite(PIN_Din, (addr & (1L << i)) ? HIGH : LOW);
        SUPER_SLO_MO();
        PulseClk();
    }
}

void FlashLow::UpdateAddress_3_0(long addr)
{
    UpdateCtrl(0x01);
    UpdateAddress_start_end(addr, 3, 0);
}

void FlashLow::UpdateAddress_7_4(long addr)
{
    UpdateCtrl(0x02);
    UpdateAddress_start_end(addr, 7, 4);
}

void FlashLow::UpdateAddress_17_8(long addr)
{
    UpdateCtrl(0x03);
    UpdateAddress_start_end(addr, 17, 8);
}

void FlashLow::UpdateChip(int chip)
{
    int i;
    UpdateCtrl(0x07);
    for (i = 0; i < 4; ++i)
    {
        digitalWrite(PIN_Din, (chip & 1) ? HIGH : LOW);
        SUPER_SLO_MO();
        PulseClk();
        chip >>= 1;
    }
    PulseCtrl();
}

void FlashLow::UpdateCtrl(int ctrl)
{
    int i;
    digitalWrite(PIN_nCTRL, LOW);
    SUPER_SLO_MO();
    for (i = 0; i < 3; ++i)
    {
        int bit = ctrl & 1;
        ctrl = ctrl >> 1;
        digitalWrite(PIN_Din, bit ? HIGH : LOW);
        SUPER_SLO_MO();
        PulseClk();
    }
    digitalWrite(PIN_nCTRL, HIGH);
    SUPER_SLO_MO();
}

byte FlashLow::ReadWrite(byte data)
{
    int i;
    byte outData = 0;
    UpdateCtrl(0x00);
    for (i = 0; i < 8; ++i)
    {
        if (digitalRead(PIN_Dout) == HIGH)
        {
            outData |= 0x80;
        }
        digitalWrite(PIN_Din, (data & 1) ? HIGH : LOW);
        SUPER_SLO_MO();
        PulseClk();
        outData >>= 1;
        data >>= 1;
    }
    return outData;
}

bool FlashLow::Toggle(byte expected)
{
    bool toggling = true;
    byte data0;
    byte data1;
    Read(m_lastAddr, &data0);
    while (toggling)
    {
        Read(m_lastAddr, &data1);
        if ((data1 ^ data0) & 0x40)
        {
            // toggle bit toggling
            data0 = data1; // set up for next toggle check
        }
        else
        {
            toggling = false;
        }
    }
    return data1 == expected;
}

void FlashLow::PulseClk()
{
    digitalWrite(PIN_CLK, HIGH);
    SUPER_SLO_MO();
    digitalWrite(PIN_CLK, LOW);
    SUPER_SLO_MO();
}

void FlashLow::PulseCtrl()
{
    digitalWrite(PIN_nCTRL, LOW);
    SUPER_SLO_MO();
    digitalWrite(PIN_nCTRL, HIGH);
    SUPER_SLO_MO();
}

void FlashLow::ResetSequence()
{
    m_lastAddr = -1;

    // initialize pins before setting output mode
    digitalWrite(PIN_ENABLE, HIGH);
    digitalWrite(PIN_CLK, HIGH);
    digitalWrite(PIN_nCTRL, HIGH);
    digitalWrite(PIN_Din, HIGH);

    // set pin modes
    pinMode(PIN_ENABLE, OUTPUT);
    pinMode(PIN_nCTRL, OUTPUT);
    pinMode(PIN_Dout, INPUT);
    pinMode(PIN_Din, OUTPUT);
    pinMode(PIN_CLK, OUTPUT);

    // Execute reset sequence
    PulseClk();
    PulseClk();
    digitalWrite(PIN_nCTRL, LOW);
    PulseClk();
    PulseClk();
    PulseClk();
    digitalWrite(PIN_nCTRL, HIGH);
    SUPER_SLO_MO();
    digitalWrite(PIN_ENABLE, LOW);
    SUPER_SLO_MO();
}

void FlashLow::DirectWrite(bool enable, bool clk, bool din, bool ctrl)
{
    digitalWrite(PIN_ENABLE, enable ? (HIGH) : (LOW));
    digitalWrite(PIN_CLK, clk ? (HIGH) : (LOW));
    digitalWrite(PIN_Din, din ? (HIGH) : (LOW));
    digitalWrite(PIN_nCTRL, ctrl ? (HIGH) : (LOW));
}

void FlashLow::DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl)
{
    *enable = digitalRead(PIN_ENABLE) == HIGH;
    *clk = digitalRead(PIN_CLK) == HIGH;
    *din = digitalRead(PIN_Din) == HIGH;
    *dout = digitalRead(PIN_Dout) == HIGH;
    *ctrl = digitalRead(PIN_nCTRL) == HIGH;
}


And just to refresh, here is the code part of the Verilog for the CPLD:

       

`define ACTIVELOW 1'b0
`define ACTIVEHIGH 1'b1

module flashProgrammer(
    input pin_ENABLE,
    input pin_CLK,
    input pin_Din,
    input pin_nCTRL,
    output reg pin_Dout,

    output [17:0] pins_A,
    output pin_nWR, 
    output pin_nRD,
    output pin_nCS,
    inout [7:0] pins_D
    );

    reg [2:0] ctrlReg;
    reg [7:0] dataReg;
    reg [17:0] addrReg;
    reg [3:0] chipReg;
    wire nOE;

    reg nRDint;
    reg nWRint;
    reg nCSint;
    reg nOEint;

    assign pin_nRD = !pin_ENABLE ? nRDint : 1'bz;
    assign pin_nWR = !pin_ENABLE ? nWRint : 1'bz;
    assign pin_nCS = !pin_ENABLE ? nCSint : 1'bz;
    assign nOE = nOEint | pin_ENABLE;

    assign pins_D = (nOE==`ACTIVELOW && pin_ENABLE==`ACTIVELOW && pin_nRD==1'b1) ? dataReg : 8'bzzzzzzzz;
    assign pins_A = (pin_ENABLE == `ACTIVELOW) ? addrReg : 18'bzzzzzzzzzzzzzzzzzz;

    always @(posedge pin_nCTRL) begin
        // Strobe out of the chip
        nRDint <= chipReg[0];
        nWRint <= chipReg[1];
        nCSint <= chipReg[2];
        nOEint <= chipReg[3];
    end

    always @(posedge pin_CLK) begin

        if (pin_nCTRL == `ACTIVELOW) begin

            // clocking in control
            pin_Dout <= ctrlReg[0];
            ctrlReg <= {pin_Din, ctrlReg[2:1]}; 

            if (pin_ENABLE == 1'b1) begin
                chipReg <= 4'b1111;
            end
        end
        else begin
            case (ctrlReg)
                3'b000 : begin
                    pin_Dout <= dataReg[0];
                    dataReg <= { pin_Din, dataReg[7:1]};
                end
                3'b001 : begin
                    pin_Dout <= addrReg[0];
                    addrReg[3:0] <= { pin_Din, addrReg[3:1]};
                end
                3'b010 : begin
                    pin_Dout <= addrReg[4];
                    addrReg[7:4] <= { pin_Din, addrReg[7:5]};
                end
                3'b011 : begin
                    pin_Dout <= addrReg[8];
                    addrReg[17:8] <= { pin_Din, addrReg[17:9]};
                end
                3'b100 : begin
                end
                3'b101 : begin
                end
                3'b110 : begin
                end
                3'b111 : begin
                    pin_Dout <= chipReg[0];
                    chipReg <= { pin_Din, chipReg[3:1]};
                    // If reading, read now
                    if ((pin_nRD | nOE) == `ACTIVELOW) begin
                        dataReg <= pins_D;
                    end
                end
            endcase
        end
    end

endmodule

BTW, this has the bug fix described in the previous post. The actual CPLD I have doesn't update Dout properly while shifting ctrlReg.

No comments:

Post a Comment