Skip to content

Commit

Permalink
adc: Repetitive buffer management
Browse files Browse the repository at this point in the history
This commit changes the behavior of the driver when it reports
buffer results back through the callback.

Originally, the driver reported a callback after each sequence
table round signaled by an interrupt. If in repetitive mode,
each reported result was put in the next buffer element,
which was considered circular, and reported back with callback.

Now the behavior changes. If in repetitive mode, each sequence table
round reported by an interruption puts the data  in next element of
the reception buffer. The callback reports back once the buffer is
fulled and stops the sampling process.

Change-Id: I3707574cfaf5dfc874473f38c5dfa88dd392133d
Signed-off-by: Juan Manuel Cruz <[email protected]>
  • Loading branch information
jmcruzal authored and nashif committed Feb 6, 2016
1 parent 51a5b96 commit 41771e5
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 17 deletions.
72 changes: 55 additions & 17 deletions drivers/adc/adc_dw.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,10 @@ static int adc_dw_read(struct device *dev, struct adc_seq_table *seq_tbl)

sys_out32(ctrl | ADC_SEQ_PTR_RST, adc_base + ADC_CTRL);

int num_entries = seq_tbl->num_entries;

info->entries = seq_tbl->entries;
for (i = 0; i < num_entries; i++) {
info->index[i] = 0;
}

#ifdef CONFIG_ADC_DW_REPETITIVE
memset(info->index, 0, seq_tbl->num_entries);
#endif
info->state = ADC_STATE_SAMPLING;
sys_out32(START_ADC_SEQ, adc_base + ADC_CTRL);

Expand Down Expand Up @@ -398,34 +395,73 @@ int adc_dw_init(struct device *dev)
return 0;
}

#ifdef CONFIG_ADC_DW_SINGLESHOT
void adc_dw_rx_isr(void *arg)
{
struct device *dev = (struct device *)arg;
struct device_config *dev_config = dev->config;
struct adc_config *config = dev_config->config_info;
struct adc_info *info = dev->driver_data;
uint32_t adc_base = config->reg_base;
uint32_t reg_val;
uint32_t sample_index;
struct adc_seq_entry *entries = info->entries;
uint32_t reg_val;
uint32_t seq_index;

for (sample_index = 0; sample_index < info->seq_size; sample_index++) {
int rep_index;
for (seq_index = 0; seq_index < info->seq_size; seq_index++) {
uint32_t *adc_buffer;

reg_val = sys_in32(adc_base + ADC_SET);
sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET);
rep_index = info->index[sample_index];
adc_buffer = (uint32_t *)entries[sample_index].buffer;
adc_buffer[rep_index] = sys_in32(adc_base + ADC_SAMPLE);
info->index[sample_index]++;
adc_buffer = (uint32_t *)entries[seq_index].buffer;
*adc_buffer = sys_in32(adc_base + ADC_SAMPLE);
}

/*Resume ADC state to continue new conversions*/
sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL);
reg_val = sys_in32(adc_base + ADC_SET);
sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_SET);
info->state = ADC_STATE_IDLE;

synchronous_call_complete(&info->sync);

/*Clear data A register*/
reg_val = sys_in32(adc_base + ADC_CTRL);
sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL);
}
#else /*CONFIG_ADC_DW_REPETITIVE*/
void adc_dw_rx_isr(void *arg)
{
struct device *dev = (struct device *)arg;
struct device_config *dev_config = dev->config;
struct adc_config *config = dev_config->config_info;
struct adc_info *info = dev->driver_data;
uint32_t adc_base = config->reg_base;
struct adc_seq_entry *entries = info->entries;
uint32_t reg_val;
uint32_t sequence_index;
uint8_t full_buffer_flag = 0;

for (sequence_index = 0; sequence_index < info->seq_size; sequence_index++) {
uint32_t *adc_buffer;
uint32_t repetitive_index;

repetitive_index = info->index[sequence_index];
/*API array is 8 bits array but ADC reads blocks of 32 bits with every sample.*/
if ((info->index[sample_index] * 4) >= entries[sample_index].buffer_length) {
info->index[sample_index] = 0;
if (repetitive_index >= (entries[sequence_index].buffer_length >> 2)) {
full_buffer_flag = 1;
continue;
}

reg_val = sys_in32(adc_base + ADC_SET);
sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET);
adc_buffer = (uint32_t *)entries[sequence_index].buffer;
adc_buffer[repetitive_index] = sys_in32(adc_base + ADC_SAMPLE);
repetitive_index++;
info->index[sequence_index] = repetitive_index;
}

if (config->seq_mode == IO_ADC_SEQ_MODE_SINGLESHOT) {
if (full_buffer_flag == 1) {
/*Resume ADC state to continue new conversions*/
sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL);
reg_val = sys_in32(adc_base + ADC_SET);
sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_SET);
Expand All @@ -434,9 +470,11 @@ void adc_dw_rx_isr(void *arg)
synchronous_call_complete(&info->sync);
}

/*Clear data A register*/
reg_val = sys_in32(adc_base + ADC_CTRL);
sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL);
}
#endif


void adc_dw_err_isr(void *arg)
Expand Down
2 changes: 2 additions & 0 deletions drivers/adc/adc_dw.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ struct adc_info {
device_sync_call_t sync;
/**State of execution of the driver*/
uint8_t state;
#ifdef CONFIG_ADC_DW_REPETITIVE
/**Current reception buffer index*/
uint8_t index[BUFS_NUM];
#endif
/**Sequence entries' array*/
struct adc_seq_entry *entries;
/**Sequence size*/
Expand Down

0 comments on commit 41771e5

Please sign in to comment.