Skip to content
Snippets Groups Projects
Commit fe9a6dfe authored by Terraneo Federico's avatar Terraneo Federico
Browse files

- Added -f option to rm in Makefile and miosix/Makefile, so that when

  doing make clean on an already clean directory, no errors are reported
- Added DMA RX for USART1 un STM32Serial. Also fixed bugs on stm32f1.
parent 28ed6aa5
Branches
Tags
No related merge requests found
...@@ -63,7 +63,7 @@ clean-recursive: ...@@ -63,7 +63,7 @@ clean-recursive:
done done
clean-topdir: clean-topdir:
-rm $(OBJ) main.elf main.hex main.bin main.map $(OBJ:.o=.d) -rm -f $(OBJ) main.elf main.hex main.bin main.map $(OBJ:.o=.d)
main: main.elf main: main.elf
$(CP) -O ihex main.elf main.hex $(CP) -O ihex main.elf main.hex
......
...@@ -66,7 +66,7 @@ all: $(OBJ) $(BOOT_FILE) ...@@ -66,7 +66,7 @@ all: $(OBJ) $(BOOT_FILE)
$(AR) rcs libmiosix.a $(OBJ) $(AR) rcs libmiosix.a $(OBJ)
clean: clean:
-rm $(OBJ) $(BOOT_FILE) libmiosix.a $(OBJ:.o=.d) -rm -f $(OBJ) $(BOOT_FILE) libmiosix.a $(OBJ:.o=.d)
-rm -f $(BOOT_FILE:.o=.d) -rm -f $(BOOT_FILE:.o=.d)
%.o: %.s %.o: %.s
......
Changelog for Miosix np embedded OS Changelog for Miosix np embedded OS
- Added -f option to rm in Makefile and miosix/Makefile, so that when
doing make clean on an already clean directory, no errors are reported
- Added DMA RX for USART1 un STM32Serial. Also fixed bugs on stm32f1.
- Fixed a bug in STM32Serial: the position of the PPRE1 and PPRE2 bitfields - Fixed a bug in STM32Serial: the position of the PPRE1 and PPRE2 bitfields
in RCC->CFGR varies from device family. This was causing incorrect baudrate in RCC->CFGR varies from device family. This was causing incorrect baudrate
settings in some configurations. settings in some configurations.
......
...@@ -123,6 +123,14 @@ void __attribute__((noinline)) usart1txDmaImpl() ...@@ -123,6 +123,14 @@ void __attribute__((noinline)) usart1txDmaImpl()
if(ports[0]) ports[0]->IRQhandleDMAtx(); if(ports[0]) ports[0]->IRQhandleDMAtx();
} }
/**
* \internal USART1 DMA rx actual implementation
*/
void __attribute__((noinline)) usart1rxDmaImpl()
{
if(ports[0]) ports[0]->IRQhandleDMArx();
}
#ifdef _ARCH_CORTEXM3_STM32 #ifdef _ARCH_CORTEXM3_STM32
/** /**
* \internal DMA1 Channel 4 IRQ (configured as USART1 TX) * \internal DMA1 Channel 4 IRQ (configured as USART1 TX)
...@@ -134,6 +142,16 @@ void __attribute__((naked)) DMA1_Channel4_IRQHandler() ...@@ -134,6 +142,16 @@ void __attribute__((naked)) DMA1_Channel4_IRQHandler()
restoreContext(); restoreContext();
} }
/**
* \internal DMA1 Channel 5 IRQ (configured as USART1 RX)
*/
void __attribute__((naked)) DMA1_Channel5_IRQHandler()
{
saveContext();
asm volatile("bl _Z15usart1rxDmaImplv");
restoreContext();
}
#else //stm32f2 and stm32f4 #else //stm32f2 and stm32f4
/** /**
...@@ -145,6 +163,16 @@ void __attribute__((naked)) DMA2_Stream7_IRQHandler() ...@@ -145,6 +163,16 @@ void __attribute__((naked)) DMA2_Stream7_IRQHandler()
asm volatile("bl _Z15usart1txDmaImplv"); asm volatile("bl _Z15usart1txDmaImplv");
restoreContext(); restoreContext();
} }
/**
* \internal DMA2 stream 5 IRQ (configured as USART1 RX)
*/
void __attribute__((naked)) DMA2_Stream5_IRQHandler()
{
saveContext();
asm volatile("bl _Z15usart1rxDmaImplv");
restoreContext();
}
#endif #endif
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
...@@ -211,12 +239,20 @@ STM32Serial::STM32Serial(int id, int baudrate, FlowCtrl flowControl) ...@@ -211,12 +239,20 @@ STM32Serial::STM32Serial(int id, int baudrate, FlowCtrl flowControl)
RCC->AHBENR |= RCC_AHBENR_DMA1EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN;
NVIC_SetPriority(DMA1_Channel4_IRQn,15);//Lowest priority for serial NVIC_SetPriority(DMA1_Channel4_IRQn,15);//Lowest priority for serial
NVIC_EnableIRQ(DMA1_Channel4_IRQn); NVIC_EnableIRQ(DMA1_Channel4_IRQn);
//Higher priority to ensure IRQhandleDMArx() is called before
//IRQhandleInterrupt(), so that idle is set correctly
NVIC_SetPriority(DMA1_Channel5_IRQn,14);
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
#else //stm32f2, stm32f4 #else //stm32f2, stm32f4
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
NVIC_SetPriority(DMA2_Stream7_IRQn,15);//Lowest priority for serial NVIC_SetPriority(DMA2_Stream7_IRQn,15);//Lowest priority for serial
NVIC_EnableIRQ(DMA2_Stream7_IRQn); NVIC_EnableIRQ(DMA2_Stream7_IRQn);
//Higher priority to ensure IRQhandleDMArx() is called before
//IRQhandleInterrupt(), so that idle is set correctly
NVIC_SetPriority(DMA2_Stream5_IRQn,14);
NVIC_EnableIRQ(DMA2_Stream5_IRQn);
#endif #endif
port->CR3=USART_CR3_DMAT; port->CR3=USART_CR3_DMAT | USART_CR3_DMAR;
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
#ifndef _ARCH_CORTEXM3_STM32 #ifndef _ARCH_CORTEXM3_STM32
//Only stm32f2, f4 and l1 have the new alternate function mapping //Only stm32f2, f4 and l1 have the new alternate function mapping
...@@ -290,8 +326,21 @@ STM32Serial::STM32Serial(int id, int baudrate, FlowCtrl flowControl) ...@@ -290,8 +326,21 @@ STM32Serial::STM32Serial(int id, int baudrate, FlowCtrl flowControl)
} }
const unsigned int quot=2*freq/baudrate; //2*freq for round to nearest const unsigned int quot=2*freq/baudrate; //2*freq for round to nearest
port->BRR=quot/2 + (quot & 1); //Round to nearest port->BRR=quot/2 + (quot & 1); //Round to nearest
if(flowControl) port->CR3=USART_CR3_RTSE | USART_CR3_CTSE; if(flowControl==false) port->CR3 |= USART_CR3_ONEBIT;
else port->CR3 |= USART_CR3_ONEBIT | USART_CR3_RTSE | USART_CR3_CTSE;
//Enabled, 8 data bit, no parity, interrupt on character rx //Enabled, 8 data bit, no parity, interrupt on character rx
#ifdef SERIAL_1_DMA
if(this==ports[0])
{
port->CR1 = USART_CR1_UE //Enable port
| USART_CR1_IDLEIE //Interrupt on idle line
| USART_CR1_TE //Transmission enbled
| USART_CR1_RE; //Reception enabled
IRQdmaReadStart();
return;
}
#endif //SERIAL_1_DMA
port->CR1 = USART_CR1_UE //Enable port port->CR1 = USART_CR1_UE //Enable port
| USART_CR1_RXNEIE //Interrupt on data received | USART_CR1_RXNEIE //Interrupt on data received
| USART_CR1_IDLEIE //Interrupt on idle line | USART_CR1_IDLEIE //Interrupt on idle line
...@@ -344,6 +393,7 @@ ssize_t STM32Serial::writeBlock(const void *buffer, size_t size, off_t where) ...@@ -344,6 +393,7 @@ ssize_t STM32Serial::writeBlock(const void *buffer, size_t size, off_t where)
{ {
//DMA is limited to 64K //DMA is limited to 64K
size_t transferSize=min<size_t>(remaining-txBufferSize,65535); size_t transferSize=min<size_t>(remaining-txBufferSize,65535);
waitDmaTxCompletion();
writeDma(buf,transferSize); writeDma(buf,transferSize);
buf+=transferSize; buf+=transferSize;
remaining-=transferSize; remaining-=transferSize;
...@@ -352,6 +402,9 @@ ssize_t STM32Serial::writeBlock(const void *buffer, size_t size, off_t where) ...@@ -352,6 +402,9 @@ ssize_t STM32Serial::writeBlock(const void *buffer, size_t size, off_t where)
while(remaining>0) while(remaining>0)
{ {
size_t transferSize=min<size_t>(remaining,txBufferSize); size_t transferSize=min<size_t>(remaining,txBufferSize);
waitDmaTxCompletion();
//Copy to txBuffer only after DMA xfer completed, as the previous
//xfer may be using the same buffer
memcpy(txBuffer,buf,transferSize); memcpy(txBuffer,buf,transferSize);
writeDma(txBuffer,transferSize); writeDma(txBuffer,transferSize);
buf+=transferSize; buf+=transferSize;
...@@ -410,17 +463,25 @@ void STM32Serial::IRQhandleInterrupt() ...@@ -410,17 +463,25 @@ void STM32Serial::IRQhandleInterrupt()
{ {
unsigned int status=port->SR; unsigned int status=port->SR;
char c; char c;
#ifdef SERIAL_1_DMA
if(this!=ports[0] && (status & USART_SR_RXNE))
#else //SERIAL_1_DMA
if(status & USART_SR_RXNE) if(status & USART_SR_RXNE)
#endif //SERIAL_1_DMA
{ {
//Always read data, since this clears interrupt flags //Always read data, since this clears interrupt flags
c=port->DR; c=port->DR;
//If no noise nor framing nor parity error put data in buffer //If no error put data in buffer
if((status & 0x7)==0) if(rxQueue.tryPut(c)==false) /*fifo overflow*/; if((status & USART_SR_FE)==0)
if(rxQueue.tryPut(c)==false) /*fifo overflow*/;
idle=false; idle=false;
} }
if(status & USART_SR_IDLE) if(status & USART_SR_IDLE)
{ {
c=port->DR; //clears interrupt flags c=port->DR; //clears interrupt flags
#ifdef SERIAL_1_DMA
if(this==ports[0]) IRQreadDma();
#endif //SERIAL_1_DMA
idle=true; idle=true;
} }
if((status & USART_SR_IDLE) || rxQueue.size()>=rxQueueMin) if((status & USART_SR_IDLE) || rxQueue.size()>=rxQueueMin)
...@@ -456,6 +517,17 @@ void STM32Serial::IRQhandleDMAtx() ...@@ -456,6 +517,17 @@ void STM32Serial::IRQhandleDMAtx()
Scheduler::IRQfindNextThread(); Scheduler::IRQfindNextThread();
txWaiting=0; txWaiting=0;
} }
void STM32Serial::IRQhandleDMArx()
{
IRQreadDma();
idle=false;
if(rxWaiting==0) return;
rxWaiting->IRQwakeup();
if(rxWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
Scheduler::IRQfindNextThread();
rxWaiting=0;
}
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
STM32Serial::~STM32Serial() STM32Serial::~STM32Serial()
...@@ -473,10 +545,13 @@ STM32Serial::~STM32Serial() ...@@ -473,10 +545,13 @@ STM32Serial::~STM32Serial()
{ {
case 1: case 1:
#ifdef SERIAL_1_DMA #ifdef SERIAL_1_DMA
IRQdmaReadStop();
#ifdef _ARCH_CORTEXM3_STM32 #ifdef _ARCH_CORTEXM3_STM32
NVIC_DisableIRQ(DMA1_Channel4_IRQn); NVIC_DisableIRQ(DMA1_Channel4_IRQn);
NVIC_DisableIRQ(DMA1_Channel5_IRQn);
#else //stm32f2, stm32f4 #else //stm32f2, stm32f4
NVIC_DisableIRQ(DMA2_Stream7_IRQn); NVIC_DisableIRQ(DMA2_Stream7_IRQn);
NVIC_DisableIRQ(DMA2_Stream5_IRQn);
#endif #endif
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
NVIC_DisableIRQ(USART1_IRQn); NVIC_DisableIRQ(USART1_IRQn);
...@@ -495,7 +570,7 @@ STM32Serial::~STM32Serial() ...@@ -495,7 +570,7 @@ STM32Serial::~STM32Serial()
} }
#ifdef SERIAL_1_DMA #ifdef SERIAL_1_DMA
void STM32Serial::writeDma(const char *buffer, size_t size) void STM32Serial::waitDmaTxCompletion()
{ {
FastInterruptDisableLock dLock; FastInterruptDisableLock dLock;
// If a previous DMA xfer is in progress, wait // If a previous DMA xfer is in progress, wait
...@@ -510,7 +585,10 @@ void STM32Serial::writeDma(const char *buffer, size_t size) ...@@ -510,7 +585,10 @@ void STM32Serial::writeDma(const char *buffer, size_t size)
} }
} while(txWaiting); } while(txWaiting);
} }
// Setup DMA xfer }
void STM32Serial::writeDma(const char *buffer, size_t size)
{
dmaTxInProgress=true; dmaTxInProgress=true;
#ifdef _ARCH_CORTEXM3_STM32 #ifdef _ARCH_CORTEXM3_STM32
DMA1_Channel4->CPAR=reinterpret_cast<unsigned int>(&port->DR); DMA1_Channel4->CPAR=reinterpret_cast<unsigned int>(&port->DR);
...@@ -539,6 +617,58 @@ void STM32Serial::writeDma(const char *buffer, size_t size) ...@@ -539,6 +617,58 @@ void STM32Serial::writeDma(const char *buffer, size_t size)
| DMA_SxCR_EN; //Start the DMA | DMA_SxCR_EN; //Start the DMA
#endif //_ARCH_CORTEXM3_STM32 #endif //_ARCH_CORTEXM3_STM32
} }
void STM32Serial::IRQreadDma()
{
unsigned int elem=IRQdmaReadStop();
for(int i=0;i<elem;i++)
if(rxQueue.tryPut(rxBuffer[i])==false) /*fifo overflow*/;
IRQdmaReadStart();
}
void STM32Serial::IRQdmaReadStart()
{
#ifdef _ARCH_CORTEXM3_STM32
DMA1_Channel5->CPAR=reinterpret_cast<unsigned int>(&port->DR);
DMA1_Channel5->CMAR=reinterpret_cast<unsigned int>(rxBuffer);
DMA1_Channel5->CNDTR=rxQueueMin;
DMA1_Channel5->CCR=DMA_CCR4_MINC //Increment RAM pointer
| 0 //Peripheral to memory
| DMA_CCR4_TEIE //Interrupt on transfer error
| DMA_CCR4_TCIE //Interrupt on transfer complete
| DMA_CCR4_EN; //Start DMA
#else //_ARCH_CORTEXM3_STM32
DMA2_Stream5->PAR=reinterpret_cast<unsigned int>(&port->DR);
DMA2_Stream5->M0AR=reinterpret_cast<unsigned int>(rxBuffer);
DMA2_Stream5->NDTR=rxQueueMin;
DMA2_Stream5->CR=DMA_SxCR_CHSEL_2 //Select channel 4 (USART_RX)
| DMA_SxCR_MINC //Increment RAM pointer
| 0 //Peripheral to memory
| DMA_SxCR_HTIE //Interrupt on half transfer
| DMA_SxCR_TEIE //Interrupt on transfer error
| DMA_SxCR_DMEIE //Interrupt on direct mode error
| DMA_SxCR_EN; //Start the DMA
#endif //_ARCH_CORTEXM3_STM32
}
int STM32Serial::IRQdmaReadStop()
{
#ifdef _ARCH_CORTEXM3_STM32
DMA1_Channel5->CCR=0;
DMA1->IFCR=DMA_IFCR_CGIF5;
return rxQueueMin-DMA1_Channel5->CNDTR;
#else //_ARCH_CORTEXM3_STM32
//Stop DMA and wait for it to actually stop
DMA2_Stream5->CR&= ~DMA_SxCR_EN;
while(DMA2_Stream5->CR & DMA_SxCR_EN) ;
DMA2->HIFCR=DMA_HIFCR_CTCIF5
| DMA_HIFCR_CHTIF5
| DMA_HIFCR_CTEIF5
| DMA_HIFCR_CDMEIF5
| DMA_HIFCR_CFEIF5;
return rxQueueMin-DMA2_Stream5->NDTR;
#endif //_ARCH_CORTEXM3_STM32
}
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
} //namespace miosix } //namespace miosix
...@@ -124,6 +124,12 @@ public: ...@@ -124,6 +124,12 @@ public:
* Never call this from user code. * Never call this from user code.
*/ */
void IRQhandleDMAtx(); void IRQhandleDMAtx();
/**
* \internal the serial port DMA rx interrupts call this member function.
* Never call this from user code.
*/
void IRQhandleDMArx();
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
/** /**
...@@ -134,11 +140,33 @@ public: ...@@ -134,11 +140,33 @@ public:
private: private:
#ifdef SERIAL_1_DMA #ifdef SERIAL_1_DMA
/** /**
* Write to the serial port using DMA * Wait until a pending DMA TX completes, if any
*/
void waitDmaTxCompletion();
/**
* Write to the serial port using DMA. When the function returns, the DMA
* transfer is still in progress.
* \param buffer buffer to write * \param buffer buffer to write
* \param size size of buffer to write * \param size size of buffer to write
*/ */
void writeDma(const char *buffer, size_t size); void writeDma(const char *buffer, size_t size);
/**
* Read from DMA buffer and write data to queue
*/
void IRQreadDma();
/**
* Start DMA read
*/
void IRQdmaReadStart();
/**
* Stop DMA read
* \return the number of characters in rxBuffer
*/
int IRQdmaReadStop();
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
/** /**
...@@ -165,6 +193,9 @@ private: ...@@ -165,6 +193,9 @@ private:
/// the fact that this class must be allocated on the heap as it derives /// the fact that this class must be allocated on the heap as it derives
/// from Device, and the Miosix linker scripts never put the heap in CCM /// from Device, and the Miosix linker scripts never put the heap in CCM
char txBuffer[txBufferSize]; char txBuffer[txBufferSize];
/// This buffer emulates the behaviour of a 16550. It is filled using DMA
/// and an interrupt is fired as soon as it is half full
char rxBuffer[rxQueueMin];
bool dmaTxInProgress; ///< True if a DMA tx is in progress bool dmaTxInProgress; ///< True if a DMA tx is in progress
#endif //SERIAL_1_DMA #endif //SERIAL_1_DMA
bool idle; ///< Receiver idle bool idle; ///< Receiver idle
......
...@@ -96,6 +96,14 @@ minimize power consumption all unused GPIO must not be left floating. ...@@ -96,6 +96,14 @@ minimize power consumption all unused GPIO must not be left floating.
*/ */
void shutdown() void shutdown()
{ {
//FIXME: at the time of writing, Miosix's newlib does not yet provide the
//sys/ioctl.h header file. Replace with a call to ioctl() when ready
#ifdef WITH_FILESYSTEM
miosix::getFileDescriptorTable().ioctl(STDOUT_FILENO,IOCTL_SYNC,0);
#else //WITH_FILESYSTEM
DefaultConsole::instance().get()->ioctl(IOCTL_SYNC,0);
#endif //WITH_FILESYSTEM
#ifdef WITH_FILESYSTEM #ifdef WITH_FILESYSTEM
FilesystemManager::instance().umountAll(); FilesystemManager::instance().umountAll();
#endif //WITH_FILESYSTEM #endif //WITH_FILESYSTEM
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment