Line data Source code
1 : // --------------------------------------------------------------------------- 2 : // USB EPROM/Flash Programmer 3 : // 4 : // Copyright (2022) Robson Martins 5 : // 6 : // This work is licensed under a Creative Commons Attribution-NonCommercial- 7 : // ShareAlike 4.0 International License. 8 : // --------------------------------------------------------------------------- 9 : /** 10 : * @ingroup Firmware 11 : * @file circuits/74hc595.cpp 12 : * @brief Implementation of the 74HC595 Class. 13 : * 14 : * @author Robson Martins (https://www.robsonmartins.com) 15 : */ 16 : // --------------------------------------------------------------------------- 17 : 18 : #include "circuits/74hc595.hpp" 19 : 20 : // --------------------------------------------------------------------------- 21 : 22 80 : HC595::HC595() : oe_(false) { 23 80 : configure(); 24 80 : } 25 : 26 1 : HC595::HC595(uint sinPin, uint clkPin, uint clrPin, uint rckPin, uint oePin, 27 1 : uint pulseTime) 28 1 : : oe_(false) { 29 1 : configure(sinPin, clkPin, clrPin, rckPin, oePin, pulseTime); 30 1 : } 31 : 32 91 : void HC595::configure(uint sinPin, uint clkPin, uint clrPin, uint rckPin, 33 : uint oePin, uint pulseTime) { 34 91 : sinPin_ = sinPin; 35 91 : clkPin_ = clkPin; 36 91 : clrPin_ = clrPin; 37 91 : rckPin_ = rckPin; 38 91 : oePin_ = oePin; 39 91 : pulseTime_ = pulseTime; 40 91 : } 41 : 42 14 : void HC595::clear() { 43 14 : if (clrPin_ != 0xFF) { 44 14 : gpio_.resetPin(clrPin_); 45 14 : sleep_us(pulseTime_); 46 14 : gpio_.setPin(clrPin_); 47 : } 48 14 : if (rckPin_ != 0xFF) { 49 14 : gpio_.setPin(rckPin_); 50 14 : sleep_us(pulseTime_); 51 14 : gpio_.resetPin(rckPin_); 52 : } 53 14 : buffer_.clear(); 54 14 : } 55 : 56 10 : void HC595::outputEnable(bool value) { 57 10 : if (oePin_ != 0xFF) { 58 4 : gpio_.setPin(oePin_, !value); 59 : } 60 10 : oe_ = value; 61 10 : } 62 : 63 1 : void HC595::outputDisable() { 64 1 : outputEnable(false); 65 1 : } 66 : 67 4 : void HC595::writeByte(uint8_t value) { 68 4 : if (!value) { 69 0 : clear(); 70 0 : return; 71 : } 72 4 : writeData(&value, 1); 73 : } 74 : 75 3 : void HC595::writeWord(uint16_t value) { 76 3 : if (!value) { 77 0 : clear(); 78 1 : return; 79 : } 80 3 : if (value <= 0xFF) { 81 1 : writeByte(value & 0xFF); 82 1 : return; 83 : } 84 : uint8_t buffer[2]; 85 2 : buffer[0] = value & 0xFF; 86 2 : buffer[1] = (value & 0xFF00) >> 8; 87 2 : writeData(buffer, 2); 88 : } 89 : 90 3 : void HC595::writeDWord(uint32_t value) { 91 3 : if (!value) { 92 0 : clear(); 93 2 : return; 94 : } 95 3 : if (value <= 0xFF) { 96 1 : writeByte(value & 0xFF); 97 1 : return; 98 2 : } else if (value <= 0xFFFF) { 99 1 : writeWord(value & 0xFFFF); 100 1 : return; 101 : } 102 : uint8_t buffer[4]; 103 1 : buffer[0] = value & 0xFF; 104 1 : buffer[1] = (value & 0xFF00) >> 8; 105 1 : buffer[2] = (value & 0xFF0000) >> 16; 106 1 : buffer[3] = (value & 0xFF000000) >> 24; 107 1 : writeData(buffer, (value <= 0xFFFFFF) ? 3 : 4); 108 : } 109 : 110 29 : void HC595::writeData(const uint8_t* buffer, uint size) { 111 29 : if (!size || !buffer) { 112 0 : return; 113 : } 114 29 : if (buffer_.size() < size) { 115 5 : buffer_.resize(size); 116 : } 117 29 : if (rckPin_ != 0xFF) { 118 29 : gpio_.resetPin(rckPin_); 119 : } 120 29 : if (clrPin_ != 0xFF) { 121 29 : gpio_.resetPin(clrPin_); 122 29 : sleep_us(pulseTime_); 123 29 : gpio_.setPin(clrPin_); 124 : } 125 29 : buffer += size - 1; 126 97 : for (uint8_t* pData = buffer_.data() + size - 1; size != 0; 127 68 : size--, pData--, buffer--) { 128 68 : *pData = *buffer; 129 68 : if (sinPin_ != 0xFF && clkPin_ != 0xFF) { 130 68 : gpio_.resetPin(clkPin_); 131 612 : for (int bit = 7; bit >= 0; bit--) { 132 544 : gpio_.setPin(sinPin_, (*pData) & (1 << bit)); 133 544 : sleep_us(pulseTime_); 134 544 : gpio_.setPin(clkPin_); 135 544 : sleep_us(pulseTime_); 136 544 : gpio_.resetPin(clkPin_); 137 : } 138 : } 139 : } 140 29 : if (rckPin_ != 0xFF) { 141 29 : gpio_.setPin(rckPin_); 142 29 : sleep_us(pulseTime_); 143 29 : gpio_.resetPin(rckPin_); 144 : } 145 : } 146 : 147 15 : void HC595::setBit(uint bit, bool value) { 148 15 : uint index = bit / 8; 149 15 : if (index + 1 > buffer_.size()) { 150 4 : buffer_.resize(index + 1); 151 : } 152 15 : uint8_t data = buffer_[index]; 153 15 : uint8_t mask = 0x01 << (bit - (index * 8)); 154 15 : if (value) { 155 8 : data |= mask; 156 : } else { 157 7 : data &= ~mask; 158 : } 159 15 : buffer_[index] = data; 160 15 : writeData(buffer_.data(), buffer_.size()); 161 15 : } 162 : 163 1 : void HC595::resetBit(uint bit) { 164 1 : setBit(bit, false); 165 1 : } 166 : 167 5 : void HC595::toggleBit(uint bit) { 168 5 : uint index = bit / 8; 169 5 : if (index + 1 > buffer_.size()) { 170 1 : buffer_.resize(index + 1); 171 : } 172 5 : uint8_t data = buffer_[index]; 173 5 : uint8_t mask = 0x01 << (bit - (index * 8)); 174 5 : data ^= mask; 175 5 : buffer_[index] = data; 176 5 : writeData(buffer_.data(), buffer_.size()); 177 5 : } 178 : 179 18 : const HC595::TData& HC595::getData(void) const { 180 18 : return buffer_; 181 : } 182 : 183 21 : const bool HC595::getBit(uint bit) const { 184 21 : uint index = bit / 8; 185 21 : uint8_t data = (index < buffer_.size()) ? buffer_[index] : 0; 186 21 : uint8_t mask = 0x01 << (bit - (index * 8)); 187 21 : return (data & mask); 188 : } 189 : 190 5 : const bool HC595::getOE(void) const { 191 5 : return oe_; 192 : }