stm32: Refactor DMA interrupts
Previously, every dma interrupt handler called the same `on_irq` function which had to check the state of every dma channel. Now, each dma interrupt handler only calls an `on_irq` method for its corresponding channel or channels.
This commit is contained in:
		
							parent
							
								
									9735c38592
								
							
						
					
					
						commit
						8c45c98e41
					
				| @ -105,46 +105,37 @@ fn main() { | |||||||
|     // ========
 |     // ========
 | ||||||
|     // Generate DMA IRQs.
 |     // Generate DMA IRQs.
 | ||||||
| 
 | 
 | ||||||
|     let mut dma_irqs: HashSet<&str> = HashSet::new(); |     let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new(); | ||||||
|     let mut bdma_irqs: HashSet<&str> = HashSet::new(); |  | ||||||
| 
 | 
 | ||||||
|     for p in METADATA.peripherals { |     for p in METADATA.peripherals { | ||||||
|         if let Some(r) = &p.registers { |         if let Some(r) = &p.registers { | ||||||
|             match r.kind { |             if r.kind == "dma" || r.kind == "bdma" { | ||||||
|                 "dma" => { |                 for irq in p.interrupts { | ||||||
|                     for irq in p.interrupts { |                     dma_irqs | ||||||
|                         dma_irqs.insert(irq.interrupt); |                         .entry(irq.interrupt) | ||||||
|                     } |                         .or_default() | ||||||
|  |                         .push((p.name, irq.signal)); | ||||||
|                 } |                 } | ||||||
|                 "bdma" => { |  | ||||||
|                     for irq in p.interrupts { |  | ||||||
|                         bdma_irqs.insert(irq.interrupt); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 _ => {} |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); |     for (irq, channels) in dma_irqs { | ||||||
|     g.extend(quote! { |         let irq = format_ident!("{}", irq); | ||||||
|         #( |  | ||||||
|             #[crate::interrupt] |  | ||||||
|             unsafe fn #tokens () { |  | ||||||
|                 crate::dma::dma::on_irq(); |  | ||||||
|             } |  | ||||||
|         )* |  | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect(); |         let channels = channels | ||||||
|     g.extend(quote! { |             .iter() | ||||||
|         #( |             .map(|(dma, ch)| format_ident!("{}_{}", dma, ch)); | ||||||
|  | 
 | ||||||
|  |         g.extend(quote! { | ||||||
|             #[crate::interrupt] |             #[crate::interrupt] | ||||||
|             unsafe fn #tokens () { |             unsafe fn #irq () { | ||||||
|                 crate::dma::bdma::on_irq(); |                 #( | ||||||
|  |                     <crate::peripherals::#channels as crate::dma::sealed::Channel>::on_irq(); | ||||||
|  |                 )* | ||||||
|             } |             } | ||||||
|         )* |         }); | ||||||
|     }); |     } | ||||||
| 
 | 
 | ||||||
|     // ========
 |     // ========
 | ||||||
|     // Generate RccPeripheral impls
 |     // Generate RccPeripheral impls
 | ||||||
|  | |||||||
| @ -38,26 +38,6 @@ impl State { | |||||||
| 
 | 
 | ||||||
| static STATE: State = State::new(); | static STATE: State = State::new(); | ||||||
| 
 | 
 | ||||||
| pub(crate) unsafe fn on_irq() { |  | ||||||
|     foreach_peripheral! { |  | ||||||
|         (bdma, BDMA1) => { |  | ||||||
|             // BDMA1 in H7 doesn't use DMAMUX, which breaks
 |  | ||||||
|         }; |  | ||||||
|         (bdma, $dma:ident) => { |  | ||||||
|             let isr = pac::$dma.isr().read(); |  | ||||||
|             foreach_dma_channel! { |  | ||||||
|                 ($channel_peri:ident, $dma, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { |  | ||||||
|                     let cr = pac::$dma.ch($channel_num).cr(); |  | ||||||
|                     if isr.tcif($channel_num) && cr.read().tcie() { |  | ||||||
|                         cr.write(|_| ()); // Disable channel interrupts with the default value.
 |  | ||||||
|                         STATE.ch_wakers[$index].wake(); |  | ||||||
|                     } |  | ||||||
|                 }; |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// safety: must be called only once
 | /// safety: must be called only once
 | ||||||
| pub(crate) unsafe fn init() { | pub(crate) unsafe fn init() { | ||||||
|     foreach_interrupt! { |     foreach_interrupt! { | ||||||
| @ -150,6 +130,12 @@ foreach_dma_channel! { | |||||||
|             fn set_waker(&mut self, waker: &Waker) { |             fn set_waker(&mut self, waker: &Waker) { | ||||||
|                 unsafe { low_level_api::set_waker($index, waker) } |                 unsafe { low_level_api::set_waker($index, waker) } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             fn on_irq() { | ||||||
|  |                 unsafe { | ||||||
|  |                     low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl crate::dma::Channel for crate::peripherals::$channel_peri {} |         impl crate::dma::Channel for crate::peripherals::$channel_peri {} | ||||||
| @ -243,4 +229,18 @@ mod low_level_api { | |||||||
|             w.set_teif(channel_number as _, true); |             w.set_teif(channel_number as _, true); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Safety: Must be called with a matching set of parameters for a valid dma channel
 | ||||||
|  |     pub unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: u8, index: u8) { | ||||||
|  |         let channel_num = channel_num as usize; | ||||||
|  |         let index = index as usize; | ||||||
|  | 
 | ||||||
|  |         let isr = dma.isr().read(); | ||||||
|  |         let cr = dma.ch(channel_num).cr(); | ||||||
|  | 
 | ||||||
|  |         if isr.tcif(channel_num) && cr.read().tcie() { | ||||||
|  |             cr.write(|_| ()); // Disable channel interrupts with the default value.
 | ||||||
|  |             STATE.ch_wakers[index].wake(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -36,22 +36,6 @@ impl State { | |||||||
| 
 | 
 | ||||||
| static STATE: State = State::new(); | static STATE: State = State::new(); | ||||||
| 
 | 
 | ||||||
| pub(crate) unsafe fn on_irq() { |  | ||||||
|     foreach_peripheral! { |  | ||||||
|         (dma, $dma:ident) => { |  | ||||||
|             foreach_dma_channel! { |  | ||||||
|                 ($channel_peri:ident, $dma, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { |  | ||||||
|                     let cr = pac::$dma.st($channel_num).cr(); |  | ||||||
|                     if pac::$dma.isr($channel_num/4).read().tcif($channel_num%4) && cr.read().tcie() { |  | ||||||
|                         cr.write(|_| ()); // Disable channel interrupts with the default value.
 |  | ||||||
|                         STATE.ch_wakers[$index].wake(); |  | ||||||
|                     } |  | ||||||
|                 }; |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// safety: must be called only once
 | /// safety: must be called only once
 | ||||||
| pub(crate) unsafe fn init() { | pub(crate) unsafe fn init() { | ||||||
|     foreach_interrupt! { |     foreach_interrupt! { | ||||||
| @ -137,6 +121,12 @@ foreach_dma_channel! { | |||||||
|             fn set_waker(&mut self, waker: &Waker) { |             fn set_waker(&mut self, waker: &Waker) { | ||||||
|                 unsafe {low_level_api::set_waker($index, waker )} |                 unsafe {low_level_api::set_waker($index, waker )} | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             fn on_irq() { | ||||||
|  |                 unsafe { | ||||||
|  |                     low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl crate::dma::Channel for crate::peripherals::$channel_peri { } |         impl crate::dma::Channel for crate::peripherals::$channel_peri { } | ||||||
| @ -240,4 +230,18 @@ mod low_level_api { | |||||||
|             w.set_teif(isrbit, true); |             w.set_teif(isrbit, true); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /// Safety: Must be called with a matching set of parameters for a valid dma channel
 | ||||||
|  |     pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, index: u8) { | ||||||
|  |         let channel_num = channel_num as usize; | ||||||
|  |         let index = index as usize; | ||||||
|  | 
 | ||||||
|  |         let cr = dma.st(channel_num).cr(); | ||||||
|  |         let isr = dma.isr(channel_num / 4).read(); | ||||||
|  | 
 | ||||||
|  |         if isr.tcif(channel_num % 4) && cr.read().tcie() { | ||||||
|  |             cr.write(|_| ()); // Disable channel interrupts with the default value.
 | ||||||
|  |             STATE.ch_wakers[index].wake(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -88,6 +88,11 @@ pub(crate) mod sealed { | |||||||
| 
 | 
 | ||||||
|         /// Sets the waker that is called when this channel stops (either completed or manually stopped)
 |         /// Sets the waker that is called when this channel stops (either completed or manually stopped)
 | ||||||
|         fn set_waker(&mut self, waker: &Waker); |         fn set_waker(&mut self, waker: &Waker); | ||||||
|  | 
 | ||||||
|  |         /// This is called when this channel triggers an interrupt.
 | ||||||
|  |         /// Note: Because some channels share an interrupt, this function might be
 | ||||||
|  |         /// called for a channel that didn't trigger an interrupt.
 | ||||||
|  |         fn on_irq(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user