Skip to content
This repository has been archived by the owner on Feb 13, 2019. It is now read-only.

DMA CNDTR Serial RX #48

Open
MabezDev opened this issue Feb 5, 2018 · 3 comments
Open

DMA CNDTR Serial RX #48

MabezDev opened this issue Feb 5, 2018 · 3 comments

Comments

@MabezDev
Copy link

MabezDev commented Feb 5, 2018

I am using the DMA with a circular buffer to recieve serial data on a UART, its working fine if it fills up both halves of the circ buffer. The problem I am having is how to grab the data still in the buffer when the serial data stops coming in.

In a C project at work I had used the CNDTR register in the DMA channel to figure out where in the buffer and how much data had been read after a timeout. Looking though dma.rs I see there is a function to access the CNDTR reg but its private to the crate. I am wondering if this is something that should be exposed.

I am fairly new to rust so I may be missing something obvious. I'd also like to mention that the work you are doing for embedded rust is amazing!

@japaric
Copy link
Owner

japaric commented Feb 5, 2018

I was thinking of something like this recently and I think we could have peek expose both the half that's not being modified (or has been completed) and the completed fraction of the other half. Something like this:

// [X, X, X, ?, ?, ?, ?, ?, X, X, X, X, X, X, X, X]
//  ~~~~~~~ in progress     ~~~~~~~~~~~~~~~~~~~~~~ completed
// "?" = to be written by the DMA
circ_buffer.peek(
    |in_progress_half: &[u8], completed_half: &[u8; 16], half: Half| {
//   ~~~~~~~~~~~~~~~~ NEW!
        let n = half_being_modified.len();
        let cndtr = if half == Half::Second {
            32 - n
        } else {
            16 - n
        };
    },
);

There may be some more descriptive names for the halves ...

Thoughts? Perhaps there should be two methods?

@MabezDev
Copy link
Author

MabezDev commented Feb 6, 2018

This looks promising. To keep things simpler, what about just returning each half of the buffer based on the half given as a param? E.g if you pass Half::Second you would get the current state of thye second part of the buffer, which could be either the full amount or a fraction of the buffer.

circ_buffer.peek(
    |requested_half_buf: &[u8], half: Half| {
//   ~~~~~~~~~~~~~~~~ NEW!
        let n = half_requested.len();
        let cndtr = if half == Half::Second {
            32 - n
        } else {
            16 - n
        };
    },
);

@thenewwazoo
Copy link

thenewwazoo commented May 4, 2018

Here is my solution. I call this when my USART line goes idle:

pub fn partial_peek<R, F, T>(&mut self, f: F) -> Result<R, Error>
    where
    F: FnOnce(&[T], Half) -> Result<(usize, R), ()>,
    B: Unsize<[T]>,
{
    // this inverts expectation and returns the half being _written_
    let buf = match self.readable_half {
        Half::First => &self.buffer[1],
        Half::Second => &self.buffer[0],
    };

    //                          ,- half-buffer
    //    [ x x x x y y y y y z | z z z z z z z z z z ]
    //                       ^- pending=11
    let pending = self.channel.get_cndtr() as usize; // available bytes in _whole_ buffer

    let slice: &[T] = buf;
    let capacity = slice.len(); // capacity of _half_ a buffer
    //     <--- capacity=10 --->
    //    [ x x x x y y y y y z | z z z z z z z z z z ]

    let pending = if pending > capacity {
        pending - capacity
    } else {
        pending
    };

    //                          ,- half-buffer
    //    [ x x x x y y y y y z | z z z z z z z z z z ]
    //                       ^- pending=1

    let end = capacity - pending;
    //    [ x x x x y y y y y z | z z z z z z z z z z ]
    //                       ^- end=9
    //             ^- consumed_offset=4
    //             [y y y y y] <-- slice
    let slice = &slice[self.consumed_offset..end];

    match f(slice, self.readable_half) {
        Ok((l, r)) => { self.consumed_offset += l; Ok(r) },
        Err(_) => Err(Error::BufferError),
    }
}

Not included in the listing is the addition of the consumed_offset: usize member of CircBuffer

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants