New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DMA CNDTR Serial RX #48

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

Comments

Projects
None yet
3 participants
@MabezDev

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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 join this conversation on GitHub. Already have an account? Sign in to comment