@@ -60,7 +60,95 @@ PixelMapper::~PixelMapper() {
60
60
delete [] buffer_;
61
61
}
62
62
63
+
// Different panel types use different techniques to set the row address.
64
+
// We abstract that away with different implementations of RowAddressSetter
65
+
class RowAddressSetter {
66
+
public:
67
+
virtual ~RowAddressSetter() {}
68
+
virtual gpio_bits_t need_bits() const = 0;
69
+
virtual void SetRowAddress(GPIO *io, int row) = 0;
70
+
};
71
+
72
+
namespace {
73
+
74
+
// The default DirectRowAddressSetter just sets the address in parallel
75
+
// output lines ABCDE with A the LSB and E the MSB.
76
+
class DirectRowAddressSetter : public RowAddressSetter {
77
+
public:
78
+
DirectRowAddressSetter(int double_rows, const HardwareMapping &h)
79
+
: row_mask_(0), last_row_(-1) {
80
+
assert(double_rows <= 32); // need to resize row_lookup_
81
+
if (double_rows >= 32) row_mask_ |= h.e;
82
+
if (double_rows >= 16) row_mask_ |= h.d;
83
+
if (double_rows >= 8) row_mask_ |= h.c;
84
+
if (double_rows >= 4) row_mask_ |= h.b;
85
+
row_mask_ |= h.a;
86
+
for (int i = 0; i < double_rows; ++i) {
87
+
// To avoid the bit-fiddle in the critical path, utilize
88
+
// a lookup-table for all possible rows.
89
+
gpio_bits_t row_address = (i & 0x01) ? h.a : 0;
90
+
row_address |= (i & 0x02) ? h.b : 0;
91
+
row_address |= (i & 0x04) ? h.c : 0;
92
+
row_address |= (i & 0x08) ? h.d : 0;
93
+
row_address |= (i & 0x10) ? h.e : 0;
94
+
row_lookup_[i] = row_address;
95
+
}
96
+
}
97
+
98
+
virtual gpio_bits_t need_bits() const { return row_mask_; }
99
+
100
+
virtual void SetRowAddress(GPIO *io, int row) {
101
+
if (row == last_row_) return;
102
+
io->WriteMaskedBits(row_lookup_[row], row_mask_);
103
+
last_row_ = row;
104
+
}
105
+
106
+
private:
107
+
gpio_bits_t row_mask_;
108
+
gpio_bits_t row_lookup_[32];
109
+
int last_row_;
110
+
};
111
+
112
+
// This is mostly experimental at this point. It works with the one panel I have
113
+
// seen that does AB, but might need smallish tweaks to work with all panels
114
+
// that do this.
115
+
class ShiftRegisterRowAddressSetter : public RowAddressSetter {
116
+
public:
117
+
ShiftRegisterRowAddressSetter(int double_rows, const HardwareMapping &h)
118
+
: double_rows_(double_rows),
119
+
row_mask_(h.a | h.b), clock_(h.a), data_(h.b),
120
+
last_row_(-1) {
121
+
}
122
+
virtual gpio_bits_t need_bits() const { return row_mask_; }
123
+
124
+
virtual void SetRowAddress(GPIO *io, int row) {
125
+
if (row == last_row_) return;
126
+
for (int activate = 0; activate < double_rows_; ++activate) {
127
+
io->ClearBits(clock_);
128
+
if (activate == double_rows_ - 1 - row) {
129
+
io->ClearBits(data_);
130
+
} else {
131
+
io->SetBits(data_);
132
+
}
133
+
io->SetBits(clock_);
134
+
}
135
+
io->ClearBits(clock_);
136
+
io->SetBits(clock_);
137
+
last_row_ = row;
138
+
}
139
+
140
+
private:
141
+
const int double_rows_;
142
+
const gpio_bits_t row_mask_;
143
+
const gpio_bits_t clock_;
144
+
const gpio_bits_t data_;
145
+
int last_row_;
146
+
};
147
+
148
+
}
149
+
63
150
const struct HardwareMapping *Framebuffer::hardware_mapping_ = NULL;
151
+
RowAddressSetter *Framebuffer::row_setter_ = NULL;
64
152
65
153
Framebuffer::Framebuffer(int rows, int columns, int parallel,
66
154
int scan_mode,
@@ -155,7 +243,8 @@ Framebuffer::~Framebuffer() {
155
243
156
244
/* static */ void Framebuffer::InitGPIO(GPIO *io, int rows, int parallel,
157
245
bool allow_hardware_pulsing,
158
-
int pwm_lsb_nanoseconds) {
246
+
int pwm_lsb_nanoseconds,
247
+
int row_address_type) {
159
248
if (sOutputEnablePulser != NULL)
160
249
return; // already initialized.
161
250
@@ -174,11 +263,18 @@ Framebuffer::~Framebuffer() {
174
263
}
175
264
176
265
const int double_rows = rows / SUB_PANELS_;
177
-
if (double_rows >= 32) all_used_bits |= h.e;
178
-
if (double_rows >= 16) all_used_bits |= h.d;
179
-
if (double_rows >= 8) all_used_bits |= h.c;
180
-
if (double_rows >= 4) all_used_bits |= h.b;
181
-
all_used_bits |= h.a;
266
+
switch (row_address_type) {
267
+
case 0:
268
+
row_setter_ = new DirectRowAddressSetter(double_rows, h);
269
+
break;
270
+
case 1:
271
+
row_setter_ = new ShiftRegisterRowAddressSetter(double_rows, h);
272
+
break;
273
+
default:
274
+
assert(0); // unexpected type.
275
+
}
276
+
277
+
all_used_bits |= row_setter_->need_bits();
182
278
183
279
// Initialize outputs, make sure that all of these are supported bits.
184
280
const uint32_t result = io->InitOutputs(all_used_bits);
@@ -415,10 +511,6 @@ void Framebuffer::DumpToMatrix(GPIO *io) {
415
511
416
512
color_clk_mask |= h.clock;
417
513
418
-
const gpio_bits_t row_mask = h.a | h.b | h.c | h.d | h.e;
419
-
420
-
gpio_bits_t row_address;
421
-
422
514
// info needed for interlace mode.
423
515
uint8_t rot_bits = 0;
424
516
switch (double_rows_) {
@@ -441,12 +533,6 @@ void Framebuffer::DumpToMatrix(GPIO *io) {
441
533
d_row = ((row_loop << 1) | (row_loop >> rot_bits)) & row_mask_;
442
534
}
443
535
444
-
row_address = (d_row & 0x01) ? h.a : 0;
445
-
row_address |= (d_row & 0x02) ? h.b : 0;
446
-
row_address |= (d_row & 0x04) ? h.c : 0;
447
-
row_address |= (d_row & 0x08) ? h.d : 0;
448
-
row_address |= (d_row & 0x10) ? h.e : 0;
449
-
450
536
// Rows can't be switched very quickly without ghosting, so we do the
451
537
// full PWM of one row before switching rows.
452
538
for (int b = kBitPlanes - pwm_to_show; b < kBitPlanes; ++b) {
@@ -464,7 +550,8 @@ void Framebuffer::DumpToMatrix(GPIO *io) {
464
550
sOutputEnablePulser->WaitPulseFinished();
465
551
466
552
// Setting address and strobing needs to happen in dark time.
467
-
io->WriteMaskedBits(row_address, row_mask); // Set row address
553
+
row_setter_->SetRowAddress(io, d_row);
554
+
468
555
io->SetBits(h.strobe); // Strobe in the previously clocked in row.
469
556
io->ClearBits(h.strobe);
470
557
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4