STM32F429 FMC SDRAM issue when column adress > 8bit - stm32f4

I have the issue with FMC controller when interfacing 64MB IS42S16400J-7BLI.
I'm using the CubeMX to set base configuration
static void MX_FMC_Init(void)
{
FMC_SDRAM_TimingTypeDef SdramTiming;
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_11;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler();
}
}
and config the memory
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef* hsdram, FMC_SDRAM_CommandTypeDef* Command)
{
__IO uint32_t tmpmrd = 0;
/* Step 3: Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 4: Insert 100 ms delay */
HAL_Delay(100);
/* Step 5: Configure a PALL (precharge all) command */
Command->CommandMode = FMC_SDRAM_CMD_PALL;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 6 : Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 4;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 7: Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
The memory and micro are connected according to the schematic
I can use only 8bit of addressing. In this configuration everything is perfect, i.e. I can read/write values and observe them in debug window. It limits me though to only 8MB of memory.
When I modify in settings 8bits up to 9/10/11bits to have more memory available it starts malfunctioning,i.e. garbage in some memory area.
I made customized board, but the same issue you going find on the STM32F429-disco board. So I reject rather the connections. I tried to play with the time delays like "Row to column delay" and increase all delays possible, but not luck. Any help would be appreciated.

From IS42S16400J-7BLI datasheet:
Internally configured as a quad-bank DRAM with a synchronous
interface. Each 16,777,216-bit bank is organized as 4,096 rows by 256
columns by 16 bits.
So, you should use 8 bit in ColumnBitsNumber. And you'll get 8 Mbytes (64 MBits/8) of memory.

Related

programming PIC32MX250F128B with Pickit3

I am successfully programming PIC32MX250F128B using Pickit3. I have written a code where, when I press a I am getting 100 data from vibration sensor. Now if I want to get another 100 data, either I have to disconnect and then reconnect the 10k ohm pull up resistor connected to MCLR pin or have to run the program again.
Is there any other way I can reset the pickit?
Here is the code I am using:
#include <p32xxxx.h> // include chip specific header file
#include <plib.h> // include peripheral library functions
// Configuration Bits
#pragma config FNOSC = FRCPLL // Internal Fast RC oscillator (8 MHz) w/ PLL
#pragma config FPLLIDIV = DIV_2 // Divide FRC before PLL (now 4 MHz)
#pragma config FPLLMUL = MUL_20 // PLL Multiply (now 80 MHz)
#pragma config FPLLODIV = DIV_2 // Divide After PLL (now 40 MHz)
// see figure 8.1 in datasheet for more info
#pragma config FWDTEN = OFF // Watchdog Timer Disabled
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select
#pragma config JTAGEN = OFF // Disable JTAG
#pragma config FSOSCEN = OFF // Disable Secondary Oscillator
#pragma config FPBDIV = DIV_1 // PBCLK = SYCLK
// Defines
#define SYSCLK 40000000L
// Macros
// Equation to set baud rate from UART reference manual equation 21-1
#define Baud2BRG(desired_baud) ( (SYSCLK / (16*desired_baud))-1)
// Function Prototypes
int SerialTransmit(const char *buffer);
unsigned int SerialReceive(char *buffer); //, unsigned int max_size);
int UART2Configure( int baud);
short a2dvals[11000];
int adcptr,num_channels,k,i;
char sampling;
int ADC_RSLT0,totaldata,totaldata1,chunks_sent,data_count,l;
short temp;
BOOL a2don;
volatile unsigned int channel4;
void __ISR(_ADC_VECTOR, IPL2) TIMER3Handler(void) // Fonction d'interruption Timer 3
{
temp = ReadADC10(0);
a2dvals[k] = (temp);
k++;
if (k>totaldata1)// && sampling == 's')
{
T3CONCLR = 0x8000;
a2don=FALSE;
chunks_sent = 0;
totaldata = k/2;
k = 1;
}
mAD1ClearIntFlag();
}
int main(void)
{
char buf[1024]; // declare receive buffer with max size 1024
// Peripheral Pin Select
U2RXRbits.U2RXR = 4; //SET RX to RB8
RPB9Rbits.RPB9R = 2; //SET RB9 to TX
SYSTEMConfigPerformance(SYSCLK);
UART2Configure(9600); // Configure UART2 for a baud rate of 9600
U2MODESET = 0x8000; // enable UART2
ANSELBbits.ANSB2 = 1; // set RB2 (AN4) to analog
TRISBbits.TRISB2 = 1; // set RB2 as an input
//adcConfigureManual(); // Configure ADC
//AD1CON1SET = 0x8000; // Enable ADC
SerialTransmit("Hello! Enter 'a' to do ADC conversion \r\n");
unsigned int rx_size;
while( 1){
rx_size = SerialReceive(buf); //, 1024); // wait here until data is received
SerialTransmit(buf); // Send out data exactly as received
SerialTransmit("\r\n");
}
return 1;
} // END main()
/* UART2Configure() sets up the UART2 for the most standard and minimal operation
* Enable TX and RX lines, 8 data bits, no parity, 1 stop bit, idle when HIGH
* Input: Desired Baud Rate
* Output: Actual Baud Rate from baud control register U2BRG after assignment*/
int UART2Configure( int desired_baud){
U2MODE = 0; // disable autobaud, TX and RX enabled only, 8N1, idle=HIGH
U2STA = 0x1400; // enable TX and RX
U2BRG = Baud2BRG(desired_baud); // U2BRG = (FPb / (16*baud)) - 1
// Calculate actual assigned baud rate
int actual_baud = SYSCLK / (16 * (U2BRG+1));
return actual_baud;
} // END UART2Configure()
/* SerialTransmit() transmits a string to the UART2 TX pin MSB first
*
* Inputs: *buffer = string to transmit */
int SerialTransmit(const char *buffer)
{
unsigned int size = strlen(buffer);
while( size)
{
while( U2STAbits.UTXBF); // wait while TX buffer full
U2TXREG = *buffer; // send single character to transmit buffer
buffer++; // transmit next character on following loop
size--; // loop until all characters sent (when size = 0)
}
while( !U2STAbits.TRMT); // wait for last transmission to finish
return 0;
}
/* SerialReceive() is a blocking function that waits for data on
* the UART2 RX buffer and then stores all incoming data into *buffer
*
* Note that when a carriage return '\r' is received, a nul character
* is appended signifying the strings end
*
* Inputs: *buffer = Character array/pointer to store received data into
* max_size = number of bytes allocated to this pointer
* Outputs: Number of characters received */
unsigned int SerialReceive(char *buffer) //, unsigned int max_size)
{
//unsigned int num_char = 0;
/* Wait for and store incoming data until either a carriage return is received
* or the number of received characters (num_chars) exceeds max_size */
while(1)
{
while( !U2STAbits.URXDA); // wait until data available in RX buffer
*buffer = U2RXREG; // empty contents of RX buffer into *buffer pointer
if (*buffer == 'a')
{
int dummy,dummy1;
unsigned char tempstr[5];
SYSTEMConfig(SYSCLK, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
// the ADC ///////////////////////////////////////
// configure and enable the ADC
CloseADC10(); // ensure the ADC is off before setting the configuration
// define setup parameters for OpenADC10
// Turn module on | ouput in integer | trigger mode auto | enable autosample
// ADC_CLK_AUTO -- Internal counter ends sampling and starts conversion (Auto convert)
// ADC_AUTO_SAMPLING_ON -- Sampling begins immediately after last conversion completes; SAMP bit is automatically set
// ADC_AUTO_SAMPLING_OFF -- Sampling begins with AcquireADC10();
#define PARAM1 ADC_MODULE_ON|ADC_FORMAT_INTG32 | ADC_CLK_TMR | ADC_AUTO_SAMPLING_ON //
// define setup parameters for OpenADC10
// ADC ref external | disable offset test | disable scan mode | do 1 sample | use single buf | alternate mode off
#define PARAM2 ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_OFF | ADC_ALT_INPUT_OFF
//
// Define setup parameters for OpenADC10
// use peripherial bus clock | set sample time | set ADC clock divider
// ADC_CONV_CLK_Tcy2 means divide CLK_PB by 2 (max speed)
// ADC_SAMPLE_TIME_5 seems to work with a source resistance < 1kohm
#define PARAM3 ADC_CONV_CLK_SYSTEM | ADC_SAMPLE_TIME_5 | ADC_CONV_CLK_Tcy2 //ADC_SAMPLE_TIME_15| ADC_CONV_CLK_Tcy2
// define setup parameters for OpenADC10
// set AN4 and as analog inputs
#define PARAM4 ENABLE_AN4_ANA
// define setup parameters for OpenADC10
// do not assign channels to scan
#define PARAM5 SKIP_SCAN_ALL
// use ground as neg ref for A | use AN4 for input A
// configure to sample AN4
SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN4 ); // configure to sample AN4
OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); // configure ADC using the parameters defined above
ConfigIntADC10(ADC_INT_PRI_2 | ADC_INT_ON);
EnableADC10(); // Enable the ADC
INTEnableSystemMultiVectoredInt();
OpenTimer3(T3_OFF | T3_SOURCE_INT | T3_PS_1_1 ,0x3e8);
num_channels = 1;
totaldata1 = 10500;
a2don=TRUE;
T3CONSET = 0x8000;
k=0;
while(1)
{
while(a2don);
for(i=0;i<100;i++)
{
dummy = a2dvals[i]/1000 ;
tempstr[0] = dummy + 0x30;
dummy1 = a2dvals[i]- dummy*1000;
dummy = dummy1/100;
tempstr[1] = dummy + 0x30;
dummy1 = dummy1 - dummy*100;
dummy = dummy1/10;
tempstr[2] = dummy + 0x30;
dummy1 = dummy1 - dummy*10;
tempstr[3] = dummy1 + 0x30;
//tempstr[4] = "\0";
printf("%c%c%c%c \n", tempstr[0],tempstr[1],tempstr[2],tempstr[3]);
}
a2don=TRUE;
}
}
}
return 1;
}// END SerialReceive()
enter image description here
Thanks for your advices.
You do not need to reset the Pickit. If anything, that might be the least efficient way to do it (arguably).
Rather try something like this. Please note this is high level. You will need to make it work yourself.
void(main){
// Setup your things here
while(1){ // Your infinite loop
// Check if you received 'a' here
if (received_a == 1){ // You received a 'a'
send_data(); // Send your data
}
}
}
Without providing actual code you have written we will not be able to help you.
You use while(1) loops everywhere, and if you don't use a break; or return command you stay in that loop forever.
I think you don't need while(1) loops in the functions except in main(). Remove these and it should work.
Try drawing out your program flow in a flow chart, it should clear things up. Also consider using a state machine using switch/case. It makes it a lot clearer where you are in the code and it's easier to debug. Also, it's probably even better to use interrupts for adc and the serial port. You free up the pic to do other stuff while peripherals are doing stuff that takes time.

Using I2C dev driver

I want to configure a sensor over the I2C bus using the I2C-dev module.
The required I2C bus is up and running, however, I cannot seem to receive any data from the sensor. Could anyone please help me debug the below code. All the sensor registers are 8 bit.
int main()
{
int devFile=0;
const char *devFileName="/dev/i2c-1";
char writeBuf[2];
uint16_t readBuf[2];
uint16_t tempReading = 0;
/* Initialize I2C interface */
devFile = hdc2010_i2c_init(devFileName, HDC2010_ADDR);
/* Configuring the sensor and trigerring measurement */
writeBuf[0] = HDC2010_CONFIG;
writeBuf[1] = 0x57;
hdc2010_i2c_write(devFile, writeBuf, 2);
writeBuf[0] = HDC2010_INTERRUPT_CONFIG;
writeBuf[1] = 0x78;
hdc2010_i2c_write(devFile, writeBuf, 2);
writeBuf[0] = HDC2010_MEASUREMENT_CONFIG;
writeBuf[1] = 0x03;
hdc2010_i2c_write(devFile, writeBuf, 2);
/* Reading temperature data from the registers */
writeBuf[0] = HDC2010_TEMP_LOW;
hdc2010_i2c_write(devFile, writeBuf, 1);
readBuf[0] = hdc2010_i2c_read(devFile, 1);
writeBuf[0] = HDC2010_TEMP_HIGH;
hdc2010_i2c_write(devFile, writeBuf, 1);
readBuf[1] = hdc2010_i2c_read(devFile, 1);
/*
* Converting the temperature to readable format
* Formula Source : HDC2010 Datasheet
*/
tempReading = ((readBuf[1] << 8) | (readBuf[0]));
tempReading = ((tempReading/65536)*165)-40;
printf("\nTemp: %d\n",tempReading);
}
int hdc2010_i2c_init(const char *devFileName, int slaveAddr)
{
int devFile;
/* Opening I2C device file */
devFile=open(devFileName,O_RDWR);
if (devFile < 0)
{
printf("\nError opening the %s device file.\n",devFileName);
exit (1);
}
/* Selecting HDC2010 by its slave address */
if (ioctl(devFile,I2C_SLAVE,slaveAddr) < 0)
{
printf("\nFailed to select HDC2010(addr=%u)\n",HDC2010_ADDR);
exit (1);
}
return devFile;
}
void hdc2010_i2c_write(int devFile, char *buf, int numBytes)
{
write(devFile, buf, numBytes);
}
uint16_t hdc2010_i2c_read(int devFile, int numBytes)
{
uint16_t readBuf;
read(devFile, &readBuf, 1);
return readBuf;
}
Do I need to use SMBus commands or read/write is sufficient ?
Are there any test applications, like in the case of SPIdev ?
I don't know interface to your chip. There is a great range of possible ways to use I2C. But there is a very common way to access a device with 8-bit registers, so let's assume that is what you need.
To read a register, you want to generate the (simplified) primitive I2C sequence:
Start I2CAddr+Write RegAddr Start I2CAddr+Read [DATA] Stop
But what you are doing is this:
Start I2CAddr+Write RegAddr Stop
Start I2CAddr+Read [DATA] Stop
Basically, you need the read register operation to be a single transaction with one stop at the end and a repeated start between write mode and read mode. But what you are sending is two transactions.
You should not be using the read()/write() interface to i2c-dev. This interface is very simple and not suitable for most I2C transactions. Instead use the ioctl() interface and I2C_RDWR. This allows the appropriate transactions to be generated.
Since certain forms of transactions are very common, including the ones you most likely want, there is a library that has them coded already. Use i2c_smbus_read_byte_data() and i2c_smbus_write_byte_data() from the library in i2c-tools.
As for test programs, there is i2cget and i2cset, part of the above mentioned i2c-tools, that will be able to do what you want.

Convert connect address with address familiy AF_SYSTEM to human readable string

Background
I'm writing some dtrace program which tracks application socket file descriptors. Aim is to provide logs which help me spot leak of file descriptors in some very complex OS X application.
Here is my other question with very helpful answer.
Problem
I want that my program is logging address to which file descriptor has been connected to. In examples there is a code which partial do what I need: soconnect_mac.d, here is link to github.
soconnect_mac.d works great when applied on Firefox, but it completely fails in case of my application. Quick investigation shown that soconnect_mac.d is able to interpret only AF_INET (value 2) family address and som library used by my application is using AF_SYSTEM (value 32) family address.
I can't find anything which could help me convert received address to something what is human readable.
So far I've got this:
#!/usr/sbin/dtrace -s
inline int af_inet = 2 ; /* AF_INET defined in Kernel/sys/socket.h */
inline int af_inet6 = 30; /* AF_INET6 defined in Kernel/sys/socket.h */
inline int af_system = 32; /* AF_SYSTEM defined in Kernel/sys/socket.h */
… // some stuff
syscall::connect:entry
/pid == $target && isOpened[pid, arg0] == 1/
{
/* assume this is sockaddr_in until we can examine family */
this->s = (struct sockaddr_in *)copyin(arg1, arg2);
this->f = this->s->sin_family;
self->fileDescriptor = arg0;
}
/* this section is copied with pride from "soconnect_mac.d" */
syscall::connect:entry
/this->f == af_inet/
{
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8;
/*
* Convert an IPv4 address into a dotted quad decimal string.
* Until the inet_ntoa() functions are available from DTrace, this is
* converted using the existing strjoin() and lltostr(). It's done in
* two parts to avoid exhausting DTrace registers in one line of code.
*/
this->a = (uint8_t *)&this->s->sin_addr;
this->addr1 = strjoin(lltostr(this->a[0] + 0ULL),
strjoin(".",
strjoin(lltostr(this->a[1] + 0ULL),
".")));
this->addr2 = strjoin(lltostr(this->a[2] + 0ULL),
strjoin(".",
lltostr(this->a[3] + 0ULL)));
self->address = strjoin(this->addr1, this->addr2);
}
/* this section is my */
syscall::connect:entry
/this->f == af_system/
{
/* TODO: Problem how to handle AF_SYSTEM address family */
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8; // this also doen't work as it should
self->address = "system family address needed here";
}
// a fallback
syscall::connect:entry
/this->f && this->f != af_inet && this->f != af_system/
{
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8;
self->address = strjoin("Can't handle family: ", lltostr(this->f));
}
syscall::connect:return
/self->fileDescriptor/
{
this->errstr = err[errno] != NULL ? err[errno] : lltostr(errno);
printf("%Y.%03d FD:%d Status:%s Address:%s Port:%d",
walltimestamp, walltimestamp % 1000000000 / 1000000,
self->fileDescriptor, this->errstr, self->address, self->port);
self->fileDescriptor = 0;
self->address = 0;
self->port = 0;
}
What is even more annoying my code has failed to read port number (I get 512 value instead one of this: 443, 8443, 5061).
IMO problem is first syscall::connect:entry where it is assumed that second argument can be treated as struct sockaddr_in. I'm guessing struct sockaddr_storage should be used in case of AF_SYSTEM address family, but I didn't found any documentation or source code which proves this in direct way.
My section with this->f == af_system condition properly catches events from application I'm investigating.

dsPIC33EV256GM002 PWM settings

I developed a simple program to produce PWM waveform on dsPIC33EV256GM002 but I can't disable it. I used PWM1 and PWM2 and I would generate PWM waveform on PWM1L1 pin (pin 26 on DIP package) maintain PWM1H1 (pin 25 on DIP package) as digital I/O.
Teorically the PWM register setting:
IOCON1bits.PENL = 1; /* PWM1L is controlled by PWM module /
IOCON1bits.PENH = 0; / PWM1H is controlled by GPIO module */
should do that but, using and oscilloscope, I noticed the PWM waveform on PWM1H1 pin, with opposite value (when PWM1L is 1 PWM1H is 0 and veceversa) even if it should be a digital I/O.
Did you find any similar problem ?
Thank you very much for your help and cooperation
regards
I used the following code:
TRISBbits.TRISB10 = 0; /* Set as a digital output */
TRISBbits.TRISB11 = 0; /* Set as a digital output */
TRISBbits.TRISB12 = 0; /* Set as a digital output */
TRISBbits.TRISB13 = 0; /* Set as a digital output */
TRISBbits.TRISB14 = 0; /* Set as a digital output */
TRISBbits.TRISB15 = 0; /* Set as a digital output */
LATBbits.LATB10 = 0; /* Set as a digital output */
LATBbits.LATB11 = 0; /* Set as a digital output */
LATBbits.LATB12 = 0; /* Set as a digital output */
LATBbits.LATB13 = 0; /* Set as a digital output */
LATBbits.LATB14 = 0; /* Set as a digital output */
LATBbits.LATB15 = 0; /* Set as a digital output */
PORTBbits.RB10=0;
PORTBbits.RB11=0;
PORTBbits.RB12=0;
PORTBbits.RB13=0;
PORTBbits.RB14=0;
PORTBbits.RB15=0;
PTPER = 4000;
/*~~~~~~~~~~ PWM1 Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
IOCON1bits.PENL = 1; /* PWM1L is controlled by PWM module */
IOCON1bits.PENH = 0; /* PWM1H is controlled by GPIO module */
IOCON1bits.PMOD = 0; /* Select Independent Output PWM mode */
PDC1 = 500; /* Initial Duty cycle */
DTR1 = 0; /* Deadtime setting */
ALTDTR1 = 0; /* Deadtime setting */
PHASE1 = 0; /* No phase shift */
/*~~~~~~~~~~~ PWM2 Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
IOCON2bits.PENH = 1; /* PWM2H is controlled by PWM module */
IOCON2bits.PENL = 0; /* PWM2L is controlled by GPIO module */
IOCON2bits.PMOD = 0; /* Select Independent Output PWM mode */
PDC2 = 2000; /* Initial Duty cycle */
DTR2 = 0; /* Deadtime setting */
ALTDTR2 = 0; /* Deadtime setting */
PHASE2 = 0; /* */
PTCONbits.PTEN = 1; /* Enable the PWM Module */
The problem was related to the write protection of IOCONxbits register.
I added the following line:
_FDEVOPT( PWMLOCK_OFF );
and this fixed the problem.
I faced same problem with dspic33ev32GP002 and changed configuration bits like so:
// FDEVOPT
#pragma config PWMLOCK = OFF
This worked for me.

Why dsPIC30F4012 resets?

I have a small circuit withy dsPIC30F4012, sometimes it works ok but sometimes without any reason randomly resets back to start of the program.
Powered by 3V MCLR has 10k resistor
Some settings:
_FOSC(CSW_FSCM_OFF & FRC_PLL4 & CSW_ON_FSCM_OFF & CSW_FSCM_OFF);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & MCLR_DIS & PWRT_OFF & BORV20);
_FGS(CODE_PROT_OFF & GWRP_OFF);
#define TMR1_PERIOD 7369
{
TMR1 = 0; /* clear timer1 register */
PR1 = TMR1_PERIOD; /* set period1 register */
T1CONbits.TCS = 0; /* set internal clock source */
IPC0bits.T1IP = 4; /* set priority level */
IFS0bits.T1IF = 0; /* clear interrupt flag */
IEC0bits.T1IE = 1; /* enable interrupts */
SRbits.IPL = 3; /* enable CPU priority levels 4-7 */
T1CONbits.TON = 1; /* start the timer */
}
/****** START OF INTERRUPT SERVICE ROUTINES *********/
void __attribute__((__interrupt__, __shadow__, __no_auto_psv__ )) _T1Interrupt(void)
{
Timer1 ++;
Timer2 ++;
Timer3 ++;
Timer4 ++;
MainCounter++;
IFS0bits.T1IF = 0; /* clear interrupt flag */
return;
}
RESET the processor can be invoked for the following reasons: start power supply, reset signal input /MCLR or WDT overflow.
Be careful: Before switching the prescaler between Timer0 and WDT Modules are recommended TMR0 and WDT reset, otherwise it may be accidental (unintentional) reset the processor.
Check it out.

Resources