Skip to content

Commit eda524f

Browse files
committed
add double buffering
1 parent 1db7f36 commit eda524f

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
@@ -1048,17 +1048,47 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) {
10481048
}
10491049

10501050
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self,
1051-
const sm_buf_info *once_write_buf, const sm_buf_info *loop_write_buf, const sm_buf_info *write_loop2_buf,
1051+
const sm_buf_info *once_write_buf, const sm_buf_info *loop_write_buf, const sm_buf_info *loop2_write_buf,
10521052
uint8_t stride_in_bytes, bool swap) {
10531053

10541054
uint8_t pio_index = pio_get_index(self->pio);
10551055
uint8_t sm = self->state_machine;
10561056

1057-
int pending_buffers_write = (once_write_buf->info.len != 0) + (loop_write_buf->info.len != 0);
1057+
int pending_buffers_write = (once_write_buf->info.len != 0) + (loop_write_buf->info.len != 0) + (loop2_write_buf->info.len != 0);
1058+
1059+
// If all buffer arguments have nonzero length, write once_write_buf, loop_write_buf, loop2_write_buf and repeat last two forever
1060+
10581061
if (!once_write_buf->info.len) {
1059-
once_write_buf = loop_write_buf;
1062+
if (!loop_write_buf->info.len) {
1063+
// If once_write_buf and loop_write_buf have zero length, write loop2_write_buf forever
1064+
once_write_buf = loop2_write_buf;
1065+
loop_write_buf = loop2_write_buf;
1066+
} else {
1067+
if (!loop2_write_buf->info.len) {
1068+
// If once_write_buf and loop2_write_buf have zero length, write loop_write_buf forever
1069+
once_write_buf = loop_write_buf;
1070+
loop2_write_buf = loop_write_buf;
1071+
} else {
1072+
// If only once_write_buf has zero length, write loop_write_buf, loop2_write_buf, and repeat last two forever
1073+
once_write_buf = loop_write_buf;
1074+
loop_write_buf = loop2_write_buf;
1075+
loop2_write_buf = once_write_buf;
1076+
}
1077+
}
1078+
} else {
1079+
if (!loop_write_buf->info.len) {
1080+
// 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
1081+
loop_write_buf = loop2_write_buf;
1082+
} else {
1083+
if (!loop2_write_buf->info.len) {
1084+
// 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
1085+
loop2_write_buf = loop_write_buf;
1086+
}
1087+
}
10601088
}
10611089

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

10771107
common_hal_mcu_disable_interrupts();
1078-
self->once_write_buf = *once_write_buf;
1079-
self->loop_write_buf = *loop_write_buf;
1108+
self->next_write_buf_1 = *once_write_buf;
1109+
self->next_write_buf_2 = *loop_write_buf;
1110+
self->next_write_buf_3 = *loop2_write_buf;
10801111
self->pending_buffers_write = pending_buffers_write;
10811112

1082-
if (self->dma_completed_write && self->once_write_buf.info.len) {
1113+
if (self->dma_completed_write && self->next_write_buf_1.info.len) {
10831114
rp2pio_statemachine_dma_complete_write(self, SM_DMA_GET_CHANNEL_WRITE(pio_index, sm));
10841115
self->dma_completed_write = false;
10851116
}
@@ -1103,8 +1134,10 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
11031134
dma_channel_config c_write;
11041135

11051136
self->current_write_buf = *once_write_buf;
1106-
self->once_write_buf = *loop_write_buf;
1107-
self->loop_write_buf = *loop_write_buf;
1137+
self->next_write_buf_1 = *loop_write_buf;
1138+
self->next_write_buf_2 = *loop2_write_buf;
1139+
self->next_write_buf_3 = *loop_write_buf;
1140+
11081141
self->pending_buffers_write = pending_buffers_write;
11091142
self->dma_completed_write = false;
11101143
self->background_stride_in_bytes = stride_in_bytes;
@@ -1133,8 +1166,10 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
11331166
}
11341167

11351168
void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel_write) {
1136-
self->current_write_buf = self->once_write_buf;
1137-
self->once_write_buf = self->loop_write_buf;
1169+
self->current_write_buf = self->next_write_buf_1;
1170+
self->next_write_buf_1 = self->next_write_buf_2;
1171+
self->next_write_buf_2 = self->next_write_buf_3;
1172+
self->next_write_buf_3 = self->next_write_buf_1;
11381173

11391174
if (self->current_write_buf.info.buf) {
11401175
if (self->pending_buffers_write > 0) {
@@ -1153,8 +1188,9 @@ bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_ob
11531188
uint8_t sm = self->state_machine;
11541189
rp2pio_statemachine_clear_dma_write(pio_index, sm);
11551190
memset(&self->current_write_buf, 0, sizeof(self->current_write_buf));
1156-
memset(&self->once_write_buf, 0, sizeof(self->once_write_buf));
1157-
memset(&self->loop_write_buf, 0, sizeof(self->loop_write_buf));
1191+
memset(&self->next_write_buf_1, 0, sizeof(self->next_write_buf_1));
1192+
memset(&self->next_write_buf_2, 0, sizeof(self->next_write_buf_2));
1193+
memset(&self->next_write_buf_3, 0, sizeof(self->next_write_buf_3));
11581194
self->pending_buffers_write = 0;
11591195
return true;
11601196
}
@@ -1176,9 +1212,37 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
11761212
uint8_t pio_index = pio_get_index(self->pio);
11771213
uint8_t sm = self->state_machine;
11781214

1179-
int pending_buffers_read = (once_read_buf->info.len != 0) + (loop_read_buf->info.len != 0);
1215+
int pending_buffers_read = (once_read_buf->info.len != 0) + (loop_read_buf->info.len != 0) + (loop2_read_buf->info.len != 0);
1216+
1217+
// If all buffer arguments have nonzero length, read once_read_buf, loop_read_buf, loop2_read_buf and repeat last two forever
1218+
11801219
if (!once_read_buf->info.len) {
1181-
once_read_buf = loop_read_buf;
1220+
if (!loop_read_buf->info.len) {
1221+
// If once_read_buf and loop_read_buf have zero length, read loop2_read_buf forever
1222+
once_read_buf = loop2_read_buf;
1223+
loop_read_buf = loop2_read_buf;
1224+
} else {
1225+
if (!loop2_read_buf->info.len) {
1226+
// If once_read_buf and loop2_read_buf have zero length, read loop_read_buf forever
1227+
once_read_buf = loop_read_buf;
1228+
loop2_read_buf = loop_read_buf;
1229+
} else {
1230+
// If only once_read_buf has zero length, read loop_read_buf, loop2_read_buf, and repeat last two forever
1231+
once_read_buf = loop_read_buf;
1232+
loop_read_buf = loop2_read_buf;
1233+
loop2_read_buf = once_read_buf;
1234+
}
1235+
}
1236+
} else {
1237+
if (!loop_read_buf->info.len) {
1238+
// 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
1239+
loop_read_buf = loop2_read_buf;
1240+
} else {
1241+
if (!loop2_read_buf->info.len) {
1242+
// 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
1243+
loop2_read_buf = loop_read_buf;
1244+
}
1245+
}
11821246
}
11831247

11841248
if (SM_DMA_ALLOCATED_READ(pio_index, sm)) {
@@ -1197,11 +1261,12 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
11971261
}
11981262

11991263
common_hal_mcu_disable_interrupts();
1200-
self->once_read_buf = *once_read_buf;
1201-
self->loop_read_buf = *loop_read_buf;
1264+
self->next_read_buf_1 = *once_read_buf;
1265+
self->next_read_buf_2 = *loop_read_buf;
1266+
self->next_read_buf_3 = *loop2_read_buf;
12021267
self->pending_buffers_read = pending_buffers_read;
12031268

1204-
if (self->dma_completed_read && self->once_read_buf.info.len) {
1269+
if (self->dma_completed_read && self->next_read_buf_1.info.len) {
12051270
rp2pio_statemachine_dma_complete_read(self, SM_DMA_GET_CHANNEL_READ(pio_index, sm));
12061271
self->dma_completed_read = false;
12071272
}
@@ -1226,8 +1291,9 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
12261291
dma_channel_config c_read;
12271292

12281293
self->current_read_buf = *once_read_buf;
1229-
self->once_read_buf = *loop_read_buf;
1230-
self->loop_read_buf = *loop_read_buf;
1294+
self->next_read_buf_1 = *loop_read_buf;
1295+
self->next_read_buf_2 = *loop2_read_buf;
1296+
self->next_read_buf_3 = *loop_read_buf;
12311297
self->pending_buffers_read = pending_buffers_read;
12321298
self->dma_completed_read = false;
12331299

@@ -1254,8 +1320,11 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s
12541320
}
12551321

12561322
void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel_read) {
1257-
self->current_read_buf = self->once_read_buf;
1258-
self->once_read_buf = self->loop_read_buf;
1323+
1324+
self->current_read_buf = self->next_read_buf_1;
1325+
self->next_read_buf_1 = self->next_read_buf_2;
1326+
self->next_read_buf_2 = self->next_read_buf_3;
1327+
self->next_read_buf_3 = self->next_read_buf_1;
12591328

12601329
if (self->current_read_buf.info.buf) {
12611330
if (self->pending_buffers_read > 0) {
@@ -1274,8 +1343,9 @@ bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj
12741343
uint8_t sm = self->state_machine;
12751344
rp2pio_statemachine_clear_dma_read(pio_index, sm);
12761345
memset(&self->current_read_buf, 0, sizeof(self->current_read_buf));
1277-
memset(&self->once_read_buf, 0, sizeof(self->once_read_buf));
1278-
memset(&self->loop_read_buf, 0, sizeof(self->loop_read_buf));
1346+
memset(&self->next_read_buf_1, 0, sizeof(self->next_read_buf_1));
1347+
memset(&self->next_read_buf_2, 0, sizeof(self->next_read_buf_2));
1348+
memset(&self->next_read_buf_3, 0, sizeof(self->next_read_buf_3));
12791349
self->pending_buffers_read = 0;
12801350
return true;
12811351
}

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)