Skip to content

Commit 6ff3fe8

Browse files
committed
add double buffering
1 parent 9e52138 commit 6ff3fe8

File tree

3 files changed

+107
-30
lines changed

3 files changed

+107
-30
lines changed

ports/raspberrypi/bindings/rp2pio/StateMachine.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,8 @@ static mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj
557557
static const mp_arg_t allowed_args[] = {
558558
{ MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} },
559559
{ MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
560-
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
561-
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
560+
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
561+
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
562562
};
563563
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
564564
check_for_deinit(self);
@@ -682,8 +682,8 @@ static mp_obj_t rp2pio_statemachine_background_read(size_t n_args, const mp_obj_
682682
static const mp_arg_t allowed_args[] = {
683683
{ MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} },
684684
{ MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
685-
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
686-
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
685+
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
686+
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
687687
};
688688
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
689689
check_for_deinit(self);
@@ -696,7 +696,7 @@ static mp_obj_t rp2pio_statemachine_background_read(size_t n_args, const mp_obj_
696696
size_t stride_in_bytes = 0;
697697
fill_buf_info(&once_read_info, args[ARG_once].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
698698
fill_buf_info(&loop_read_info, args[ARG_loop].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
699-
fill_buf_info(&loop2_read_info, args[ARG_loop].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
699+
fill_buf_info(&loop2_read_info, args[ARG_loop2].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
700700
if (!stride_in_bytes) {
701701
return mp_const_none;
702702
}

ports/raspberrypi/common-hal/rp2pio/StateMachine.c

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,17 +1061,47 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) {
10611061
}
10621062

10631063
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self,
1064-
const sm_buf_info *once_write_buf, const sm_buf_info *loop_write_buf, const sm_buf_info *write_loop2_buf,
1064+
const sm_buf_info *once_write_buf, const sm_buf_info *loop_write_buf, const sm_buf_info *loop2_write_buf,
10651065
uint8_t stride_in_bytes, bool swap) {
10661066

10671067
uint8_t pio_index = pio_get_index(self->pio);
10681068
uint8_t sm = self->state_machine;
10691069

1070-
int pending_buffers_write = (once_write_buf->info.len != 0) + (loop_write_buf->info.len != 0);
1070+
int pending_buffers_write = (once_write_buf->info.len != 0) + (loop_write_buf->info.len != 0) + (loop2_write_buf->info.len != 0);
1071+
1072+
// If all buffer arguments have nonzero length, write once_write_buf, loop_write_buf, loop2_write_buf and repeat last two forever
1073+
10711074
if (!once_write_buf->info.len) {
1072-
once_write_buf = loop_write_buf;
1075+
if (!loop_write_buf->info.len) {
1076+
// If once_write_buf and loop_write_buf have zero length, write loop2_write_buf forever
1077+
once_write_buf = loop2_write_buf;
1078+
loop_write_buf = loop2_write_buf;
1079+
} else {
1080+
if (!loop2_write_buf->info.len) {
1081+
// If once_write_buf and loop2_write_buf have zero length, write loop_write_buf forever
1082+
once_write_buf = loop_write_buf;
1083+
loop2_write_buf = loop_write_buf;
1084+
} else {
1085+
// If only once_write_buf has zero length, write loop_write_buf, loop2_write_buf, and repeat last two forever
1086+
once_write_buf = loop_write_buf;
1087+
loop_write_buf = loop2_write_buf;
1088+
loop2_write_buf = once_write_buf;
1089+
}
1090+
}
1091+
} else {
1092+
if (!loop_write_buf->info.len) {
1093+
// If once_write_buf has nonzero length and loop_write_buf has zero length, write once_write_buf, loop2_write_buf and repeat last buf forever
1094+
loop_write_buf = loop2_write_buf;
1095+
} else {
1096+
if (!loop2_write_buf->info.len) {
1097+
// If once_write_buf has nonzero length and loop2_write_buf have zero length, write once_write_buf, loop_write_buf and repeat last buf forever
1098+
loop2_write_buf = loop_write_buf;
1099+
}
1100+
}
10731101
}
10741102

1103+
// if DMA is already going (i.e. this is not the first call to background_write),
1104+
// block until once_write_buf and loop_write_buf have each been written at least once
10751105
if (SM_DMA_ALLOCATED_WRITE(pio_index, sm)) {
10761106
if (stride_in_bytes != self->background_stride_in_bytes) {
10771107
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched data size"));
@@ -1088,11 +1118,12 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
10881118
}
10891119

10901120
common_hal_mcu_disable_interrupts();
1091-
self->once_write_buf = *once_write_buf;
1092-
self->loop_write_buf = *loop_write_buf;
1121+
self->next_write_buf_1 = *once_write_buf;
1122+
self->next_write_buf_2 = *loop_write_buf;
1123+
self->next_write_buf_3 = *loop2_write_buf;
10931124
self->pending_buffers_write = pending_buffers_write;
10941125

1095-
if (self->dma_completed_write && self->once_write_buf.info.len) {
1126+
if (self->dma_completed_write && self->next_write_buf_1.info.len) {
10961127
rp2pio_statemachine_dma_complete_write(self, SM_DMA_GET_CHANNEL_WRITE(pio_index, sm));
10971128
self->dma_completed_write = false;
10981129
}
@@ -1116,8 +1147,10 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
11161147
dma_channel_config c_write;
11171148

11181149
self->current_write_buf = *once_write_buf;
1119-
self->once_write_buf = *loop_write_buf;
1120-
self->loop_write_buf = *loop_write_buf;
1150+
self->next_write_buf_1 = *loop_write_buf;
1151+
self->next_write_buf_2 = *loop2_write_buf;
1152+
self->next_write_buf_3 = *loop_write_buf;
1153+
11211154
self->pending_buffers_write = pending_buffers_write;
11221155
self->dma_completed_write = false;
11231156
self->background_stride_in_bytes = stride_in_bytes;
@@ -1150,8 +1183,10 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
11501183
}
11511184

11521185
void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel_write) {
1153-
self->current_write_buf = self->once_write_buf;
1154-
self->once_write_buf = self->loop_write_buf;
1186+
self->current_write_buf = self->next_write_buf_1;
1187+
self->next_write_buf_1 = self->next_write_buf_2;
1188+
self->next_write_buf_2 = self->next_write_buf_3;
1189+
self->next_write_buf_3 = self->next_write_buf_1;
11551190

11561191
if (self->current_write_buf.info.buf) {
11571192
if (self->pending_buffers_write > 0) {
@@ -1170,8 +1205,9 @@ bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_ob
11701205
uint8_t sm = self->state_machine;
11711206
rp2pio_statemachine_clear_dma_write(pio_index, sm);
11721207
memset(&self->current_write_buf, 0, sizeof(self->current_write_buf));
1173-
memset(&self->once_write_buf, 0, sizeof(self->once_write_buf));
1174-
memset(&self->loop_write_buf, 0, sizeof(self->loop_write_buf));
1208+
memset(&self->next_write_buf_1, 0, sizeof(self->next_write_buf_1));
1209+
memset(&self->next_write_buf_2, 0, sizeof(self->next_write_buf_2));
1210+
memset(&self->next_write_buf_3, 0, sizeof(self->next_write_buf_3));
11751211
self->pending_buffers_write = 0;
11761212
return true;
11771213
}
@@ -1193,9 +1229,37 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
11931229
uint8_t pio_index = pio_get_index(self->pio);
11941230
uint8_t sm = self->state_machine;
11951231

1196-
int pending_buffers_read = (once_read_buf->info.len != 0) + (loop_read_buf->info.len != 0);
1232+
int pending_buffers_read = (once_read_buf->info.len != 0) + (loop_read_buf->info.len != 0) + (loop2_read_buf->info.len != 0);
1233+
1234+
// If all buffer arguments have nonzero length, read once_read_buf, loop_read_buf, loop2_read_buf and repeat last two forever
1235+
11971236
if (!once_read_buf->info.len) {
1198-
once_read_buf = loop_read_buf;
1237+
if (!loop_read_buf->info.len) {
1238+
// If once_read_buf and loop_read_buf have zero length, read loop2_read_buf forever
1239+
once_read_buf = loop2_read_buf;
1240+
loop_read_buf = loop2_read_buf;
1241+
} else {
1242+
if (!loop2_read_buf->info.len) {
1243+
// If once_read_buf and loop2_read_buf have zero length, read loop_read_buf forever
1244+
once_read_buf = loop_read_buf;
1245+
loop2_read_buf = loop_read_buf;
1246+
} else {
1247+
// If only once_read_buf has zero length, read loop_read_buf, loop2_read_buf, and repeat last two forever
1248+
once_read_buf = loop_read_buf;
1249+
loop_read_buf = loop2_read_buf;
1250+
loop2_read_buf = once_read_buf;
1251+
}
1252+
}
1253+
} else {
1254+
if (!loop_read_buf->info.len) {
1255+
// If once_read_buf has nonzero length and loop_read_buf has zero length, read once_read_buf, loop2_read_buf and repeat last buf forever
1256+
loop_read_buf = loop2_read_buf;
1257+
} else {
1258+
if (!loop2_read_buf->info.len) {
1259+
// If once_read_buf has nonzero length and loop2_read_buf have zero length, read once_read_buf, loop_read_buf and repeat last buf forever
1260+
loop2_read_buf = loop_read_buf;
1261+
}
1262+
}
11991263
}
12001264

12011265
if (SM_DMA_ALLOCATED_READ(pio_index, sm)) {
@@ -1214,11 +1278,12 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
12141278
}
12151279

12161280
common_hal_mcu_disable_interrupts();
1217-
self->once_read_buf = *once_read_buf;
1218-
self->loop_read_buf = *loop_read_buf;
1281+
self->next_read_buf_1 = *once_read_buf;
1282+
self->next_read_buf_2 = *loop_read_buf;
1283+
self->next_read_buf_3 = *loop2_read_buf;
12191284
self->pending_buffers_read = pending_buffers_read;
12201285

1221-
if (self->dma_completed_read && self->once_read_buf.info.len) {
1286+
if (self->dma_completed_read && self->next_read_buf_1.info.len) {
12221287
rp2pio_statemachine_dma_complete_read(self, SM_DMA_GET_CHANNEL_READ(pio_index, sm));
12231288
self->dma_completed_read = false;
12241289
}
@@ -1243,8 +1308,9 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
12431308
dma_channel_config c_read;
12441309

12451310
self->current_read_buf = *once_read_buf;
1246-
self->once_read_buf = *loop_read_buf;
1247-
self->loop_read_buf = *loop_read_buf;
1311+
self->next_read_buf_1 = *loop_read_buf;
1312+
self->next_read_buf_2 = *loop2_read_buf;
1313+
self->next_read_buf_3 = *loop_read_buf;
12481314
self->pending_buffers_read = pending_buffers_read;
12491315
self->dma_completed_read = false;
12501316

@@ -1271,8 +1337,11 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
12711337
}
12721338

12731339
void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel_read) {
1274-
self->current_read_buf = self->once_read_buf;
1275-
self->once_read_buf = self->loop_read_buf;
1340+
1341+
self->current_read_buf = self->next_read_buf_1;
1342+
self->next_read_buf_1 = self->next_read_buf_2;
1343+
self->next_read_buf_2 = self->next_read_buf_3;
1344+
self->next_read_buf_3 = self->next_read_buf_1;
12761345

12771346
if (self->current_read_buf.info.buf) {
12781347
if (self->pending_buffers_read > 0) {
@@ -1291,8 +1360,9 @@ bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj
12911360
uint8_t sm = self->state_machine;
12921361
rp2pio_statemachine_clear_dma_read(pio_index, sm);
12931362
memset(&self->current_read_buf, 0, sizeof(self->current_read_buf));
1294-
memset(&self->once_read_buf, 0, sizeof(self->once_read_buf));
1295-
memset(&self->loop_read_buf, 0, sizeof(self->loop_read_buf));
1363+
memset(&self->next_read_buf_1, 0, sizeof(self->next_read_buf_1));
1364+
memset(&self->next_read_buf_2, 0, sizeof(self->next_read_buf_2));
1365+
memset(&self->next_read_buf_3, 0, sizeof(self->next_read_buf_3));
12961366
self->pending_buffers_read = 0;
12971367
return true;
12981368
}

ports/raspberrypi/common-hal/rp2pio/StateMachine.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ typedef struct sm_buf_info {
2222
mp_buffer_info_t info;
2323
} sm_buf_info;
2424

25+
#define RP2PIO_STATEMACHINE_N_BUFS 3
26+
2527
typedef struct {
2628
mp_obj_base_t base;
2729
uint32_t pins; // Bitmask of what pins this state machine uses.
@@ -49,8 +51,13 @@ typedef struct {
4951
// dma-related items
5052
volatile int pending_buffers_write;
5153
volatile int pending_buffers_read;
52-
sm_buf_info current_write_buf, once_write_buf, loop_write_buf;
53-
sm_buf_info current_read_buf, once_read_buf, loop_read_buf;
54+
int write_buf_index, read_buf_index;
55+
sm_buf_info write_buf[RP2PIO_STATEMACHINE_N_BUFS];
56+
sm_buf_info read_buf[RP2PIO_STATEMACHINE_N_BUFS];
57+
58+
sm_buf_info current_write_buf, next_write_buf_1, next_write_buf_2, next_write_buf_3;
59+
sm_buf_info current_read_buf, next_read_buf_1, next_read_buf_2, next_read_buf_3;
60+
5461
int background_stride_in_bytes;
5562
bool dma_completed_write, byteswap;
5663
bool dma_completed_read;

0 commit comments

Comments
 (0)